HDRCR-118: per-email lockout dopo 5 fallimenti consecutivi
Summary
Defense in depth contro brute-force su credenziali specifiche, indipendente dall'IP del client. Risposta strutturale al problema NAT corporate scoperto in HDRCR-117.
-
app/auth/lockout.py: counter + flag su redis con TTL-
auth:failed:<email>counter consecutivi (TTL 5 min) -
auth:locked:<email>flag di lockout (TTL 15 min)
-
- 5 fallimenti su
alice@xin 5 min → lockout 15 min sualice@xda qualunque IP - Login riuscito → reset counter
- Errore 401 generico (no user-enumeration: stesso messaggio per "sbagliata" / "lockata" / "non esiste")
- Email normalizzata (lowercase + strip) prima della chiave redis
- Degrade gracefully se redis è giù
Test plan
-
Unit test con fake redis in-memory ( tests/test_auth_lockout.py):- no lockout iniziale
- lockout dopo 5 fallimenti consecutivi
- per-email isolato (alice lockata, bob libero)
- reset clears counter+lock
- normalization (case + whitespace insensitive)
- redis-down degrade gracefully
-
Pipeline devsuccess → deploy staging -
Smoke staging: 5 password sbagliate su email X → 6° tentativo con password corretta → 401; altro account → login OK; dopo 15 min → unlock