Was macht Authentifizierungssicherheit?
Regeln
- Passwörter mit bcrypt (Kostenfaktor 12+) oder argon2id hashen — niemals im Klartext speichern oder SHA/MD5 verwenden
- Login-Endpunkte ratenbegrenzen: maximal 5 Versuche pro Minute pro IP, 10 pro Account pro Stunde
- Exponentielles Lockout implementieren: 1s, 2s, 4s, 8s... nach fehlgeschlagenen Versuchen, hartes Lockout bei 10 Fehlversuchen für 15 Minuten
- Passwort-Zurücksetzungstoken: kryptografisch zufällig, einmalig verwendbar, maximal 1 Stunde gültig
- Generische Fehlermeldungen zurückgeben: „Ungültige E-Mail oder Passwort“ — niemals preisgeben, welches Feld falsch ist
- Minimale Passwortlänge von 8 Zeichen erzwingen, gegen kompromittierte Passwortlisten prüfen (HaveIBeenPwned-API)
import bcrypt from "bcrypt";
const hash = await bcrypt.hash(password, 12);
const valid = await bcrypt.compare(password, storedHash);
if (!valid) {
await incrementFailedAttempts(userId);
return res.status(401).json({ error: "Ungültige E-Mail oder Passwort" });
}
await resetFailedAttempts(userId);
async function checkLockout(userId: string) {
const attempts = await getFailedAttempts(userId);
if (attempts.count >= 10) {
const lockoutEnd = attempts.lastAttempt + 15 * 60 * 1000;
if (Date.now() < lockoutEnd) throw new Error("Account vorübergehend gesperrt");
}
}
Vermeiden
- Passwörter im Klartext, Base64 oder mit umkehrbarer Verschlüsselung speichern
- SHA-256 für Passwörter — es ist schnell, was Brute-Force-Angriffe begünstigt
- Preisgeben, ob eine E-Mail-Adresse bei der Anmeldung oder Passwort-Zurücksetzung existiert
- Passwort-Zurücksetzungslinks, die nie ablaufen oder wiederverwendet werden können
- Unbegrenzte Anmeldeversuche von einer einzelnen IP zulassen