Chapter 2 of 8 · 5 checks · 3 min
Authentication and sessions (A07)
How you store passwords, slow down guessing and manage sessions decides whether one leaked password or cookie becomes an account takeover.
Hash passwords with Argon2id, scrypt or bcryptMust
Why it matters and how to check
Passwords must be stored with a slow, salted password hashing function, never with plain SHA-256 or MD5, and never encrypted. The OWASP Password Storage Cheat Sheet recommends Argon2id with at least 19 MiB of memory, 2 iterations and a parallelism of 1. Use scrypt if Argon2id is unavailable and bcrypt only on legacy systems, with a work factor of at least 10 and input capped at 72 bytes.
To verify, look at a stored password in your database. An Argon2id hash starts with
$argon2id$and shows its parameters. A bcrypt hash starts with$2b$or similar, and the number after it is the cost.Rate limit sign-in and offer multi-factor authenticationMust
Why it matters and how to check
Credential stuffing uses passwords leaked from other sites, and it works because people reuse them. Limit failed attempts per account and per IP, add a delay or a challenge after repeated failures, and offer MFA, ideally passkeys or an authenticator app, especially for admin accounts.
To verify, script 20 wrong passwords against one account in a minute. You should see responses slow down, a 429, or a challenge, and an alert or log entry for the burst. Then confirm every admin account has MFA turned on, and that turning MFA off requires the current password or a fresh sign-in.
Issue a new session id on login and kill it on logoutMust
Why it matters and how to check
If the session id stays the same before and after login, an attacker who planted it (session fixation) is now signed in as your user. Generate a new session id when a user signs in or raises privileges, and invalidate it on the server when they sign out. Set an idle timeout and an absolute lifetime.
To verify, note the session cookie value before login, sign in and confirm it changed. Copy the cookie, sign out, then replay the old cookie with
curl. The request must be treated as signed out. A stateless token that still works after logout means you need a server-side revocation list or short expiry.Make password reset tokens single use and short livedMust
Why it matters and how to check
A reset link is a password. Tokens should be long and random, stored hashed, valid for a short window such as 15 to 60 minutes, and dead after one use. The reset form should not reveal whether an email has an account, and a successful reset should end other active sessions.
To verify, request two resets and confirm the first link stops working. Use a link once, then open it again: it must fail. Request a reset for an address that has no account and compare the response text and timing with a real one. They should look the same.
Reject common and breached passwords instead of forcing complexity rulesShould
Why it matters and how to check
NIST SP 800-63B-4 (July 2025) says to check new passwords against a blocklist of commonly used, expected or compromised values, and not to impose other composition rules such as mixing character types. It also requires at least 15 characters when a password is the only factor, says to allow paste so password managers work, and says to verify the whole password without truncating it.
To verify, try to register with
password123andSummer2026!. Both should be refused with a clear message. Then paste a 64 character random password from a password manager and confirm it is accepted and works on the next sign-in, which also proves you are not silently truncating it.