Bremse gegen Passwortraten
Nach fuenf Fehlversuchen wird eine E-Mail-Adresse gesperrt, erst eine Minute, dann doppelt so lang, hoechstens 15 Minuten. Gezaehlt wird je Adresse, auch fuer unbekannte - sonst verriete die Sperre, welche Konten es gibt. Waehrend der Sperre kommt auch das richtige Passwort nicht durch. Jeder Versuch zaehlt sofort und wird bei Erfolg zurueckgenommen. Zwischen Sperrpruefung und Zaehlen liegt damit kein await; gleichzeitige Anfragen kommen so nicht alle an der Sperre vorbei. Der Zaehler liegt im Speicher des einen Prozesses. Ein Neustart setzt ihn zurueck - der Notausgang, falls sich das einzige Ausbilderkonto aussperrt. Beim Aufraeumen wird eine laufende Sperre nie verdraengt. Die Containerabnahme prueft die Sperre im laufenden Abbild. Das Abnahmeprotokoll ist gegen diesen Stand neu erzeugt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5fbf1ac4de
commit
31d7779f45
@@ -3,6 +3,7 @@
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { datenbank, schema } from '@/lib/db';
|
||||
import { anmeldeDrossel, wartezeitText } from '@/lib/auth/drossel';
|
||||
import { passwortPruefen } from '@/lib/auth/passwort';
|
||||
import { sitzungAnlegen, sitzungBeenden } from '@/lib/auth/sitzung';
|
||||
import { jetzt } from '@/lib/zeit';
|
||||
@@ -19,6 +20,18 @@ export async function anmelden(_vorher: Anmeldezustand, formular: FormData): Pro
|
||||
return { fehler: 'Bitte E-Mail-Adresse und Passwort eingeben.', email };
|
||||
}
|
||||
|
||||
// Während einer Sperre wird gar nicht erst geprüft – auch ein richtiges
|
||||
// Passwort kommt dann nicht durch, sonst wäre die Sperre wertlos.
|
||||
const drossel = anmeldeDrossel();
|
||||
const wartezeit = drossel.wartezeit(email);
|
||||
if (wartezeit > 0) {
|
||||
return { fehler: `Zu viele Fehlversuche. Bitte ${wartezeitText(wartezeit)} noch einmal versuchen.`, email };
|
||||
}
|
||||
// Jeder Versuch zählt sofort als Fehlversuch und wird erst bei Erfolg
|
||||
// zurückgenommen. Zwischen Prüfen und Zählen liegt so kein await – sonst
|
||||
// kämen hundert gleichzeitige Anfragen alle an der Sperre vorbei.
|
||||
drossel.fehlversuch(email);
|
||||
|
||||
const db = datenbank();
|
||||
const benutzer = db.select().from(schema.benutzer).where(eq(schema.benutzer.email, email)).get();
|
||||
|
||||
@@ -34,6 +47,8 @@ export async function anmelden(_vorher: Anmeldezustand, formular: FormData): Pro
|
||||
const stimmt = await passwortPruefen(benutzer.passwortHash, passwort);
|
||||
if (!stimmt) return abweisung;
|
||||
|
||||
drossel.erfolg(email);
|
||||
|
||||
db.update(schema.benutzer).set({ letzteAnmeldungAm: jetzt() }).where(eq(schema.benutzer.id, benutzer.id)).run();
|
||||
await sitzungAnlegen(benutzer.id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user