Anmeldesperre gegen Selbstverlaengerung und Schreiblast sichern

Die Sperre hielt sich selbst am Leben. Jeder Aufruf wurde festgehalten,
auch der, der wegen der laufenden Sperre gar nicht geprueft wurde; die
Frist lief zugleich ab dem juengsten Fehlversuch. Wer also alle zehn
Minuten ein falsches Passwort an eine fremde Adresse schickte, sperrte
deren Inhaber dauerhaft aus - ohne das Passwort zu kennen. Jeder dieser
Aufrufe hinterliess ausserdem eine Zeile, die erst der Wartungslauf nach
30 Tagen wieder los wurde.

Jetzt zwei getrennte Dinge: Ein geprueft fehlgeschlagener Versuch zaehlt
und wird einzeln festgehalten. Ein waehrend der Sperre abgewiesener
Aufruf zaehlt nicht und wird hoechstens einmal je Sperre vermerkt.

Die Auswertung geht die Versuche von alt nach neu durch und zieht die
Runden nach: Ist das Mass voll, beginnt an diesem Versuch eine Sperre
und der Zaehler faengt von vorn an. Damit laeuft die Frist auch dann ab,
wenn die Fehlversuche noch im Zeitfenster stehen - vorher blieb der
Zugang bis zum Fensterende dicht.

Die Tests sind gegen vier Mutationen geprueft; jede wird rot.

Refs #38
This commit is contained in:
Florian Wilde
2026-08-24 02:13:04 +02:00
parent 2bed78915f
commit 133b0314c5
3 changed files with 335 additions and 16 deletions
+3 -2
View File
@@ -9,6 +9,7 @@ import {
anmeldungErlaubt,
aufMindestdauerWarten,
fehlversucheZuruecksetzen,
sperreVermerken,
versuchFesthalten,
} from '@/lib/auth/ratelimit'
import { protokollieren } from '@/lib/audit'
@@ -110,7 +111,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
// 1. Sperre pruefen, bevor teuer gerechnet wird.
const sperre = await anmeldungErlaubt(email, ip)
if (sperre.gesperrt) {
await versuchFesthalten(email, ip, false, 'gesperrt')
await sperreVermerken(email, ip)
throw new AnmeldeFehler('gesperrt', sperre.nochSekunden)
}
@@ -274,7 +275,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
// anmeldet - erraten laesst sich ein Passkey ohnehin nicht.
const sperre = await anmeldungErlaubt(benutzer.email, ip)
if (sperre.gesperrt) {
await versuchFesthalten(benutzer.email, ip, false, 'gesperrt')
await sperreVermerken(benutzer.email, ip)
throw new AnmeldeFehler('gesperrt', sperre.nochSekunden)
}