SecPrep logoSecPrep

Design a rate-limiting and account-lockout system to protect login endpoints against brute force and credential stuffing.

Key Talking Points

  • Layer 1 — IP rate limiting at the edge (CDN/WAF): slow/block IPs making more than N failed attempts per minute. Use sliding-window counters in Redis for accuracy.
  • Layer 2 — Per-account progressive delays: after N failed attempts for a given username, introduce exponential back-off (e.g. 1s, 2s, 4s…) or a CAPTCHA challenge — avoid hard lockout which enables denial-of-service against a victim account.
  • Use CAPTCHA (e.g. hCaptcha, Turnstile) as a friction layer triggered by anomalous rate, not on every login (UX trade-off).
  • Check submitted passwords against known-breached databases (HIBP k-anonymity API) and force a reset if the credential appears in a breach dump.
  • For credential stuffing: distribute detection across IP clusters — if many IPs each fail once, per-IP limits miss it but a global anomaly threshold catches it.
  • Never reveal whether the failure is 'wrong password' vs 'unknown user' — return a generic 'invalid credentials' message to prevent user enumeration.
  • Alert and lock accounts only as a last resort (or require email unlock) to avoid DoS-via-lockout attacks; prefer delays + CAPTCHA over hard lock.
  • Store rate-limit counters in Redis with short TTLs; use a token-bucket or sliding-window algorithm rather than a fixed window to avoid burst exploitation at window boundaries.

Effective login protection requires layered controls: IP-based rate limiting to slow down distributed attacks, per-account lockout or progressive delays to stop targeted brute force, CAPTCHA for bot friction, and breach-password checking. No single control is sufficient alone.

Practice this in the app →