Authentication Best Practices

Chapter 2 · Practice 3 of 4

Throttle failed logins per account, with lockouts that cannot be abused

From The login flow and brute force protection

Why it matters

Attackers guess passwords against one account (brute force) or try leaked pairs across many accounts (credential stuffing). OWASP recommends tracking failures per account rather than per IP address, because attackers rotate IPs cheaply. Add a per-IP limit as well to slow down stuffing across accounts.

NIST SP 800-63B-4 caps consecutive failed attempts on one authenticator at 100, and lets you set a lower limit. Within that cap, increasing delays usually work better than a hard lock:

  1. Count consecutive failures per account over an observation window.
  2. After a few failures, add a delay that doubles each time, or ask for a CAPTCHA.
  3. Reset the counter on a successful login.

A hard lockout can be turned against you: anyone who knows a username can lock its owner out. OWASP says to keep password recovery available while an account is locked, so the real owner can still get in.

Enforce all of this on the server, with a counter store shared by every instance (a database or Redis), so a scaled-out app does not give each attacker several fresh budgets.

Do

  • Count failures per account and per source IP
  • Use growing delays or a CAPTCHA before any hard lock
  • Keep password reset usable while an account is locked
  • Store counters where every app instance can see them