EXERCISE 3 — The complete, ordered fix for the admin-login CSRF error ===================================================================== THE SYMPTOM (recap): Logging into the admin page throws "Invalid CSRF token." Clicking the browser's Back button clears it. Seen so far only in Firefox. Diagnosed (Chapter 5) as a STALE token -- the form's embedded token no longer matches the session's expected token by the time you submit -- NOT an attack. THE ORDERED FIX: STEP 1 -- Stop the login form being served stale from cache/bfcache. Add to the login page response: Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache WHY: Firefox's back/forward cache (bfcache) restores a fully-live previous login page from memory, carrying an OLD embedded token. no-store tells the browser not to reuse that page, so the form always loads with a token that matches the CURRENT session. This is the most likely single fix and directly explains the Firefox-specific behaviour (its bfcache is more aggressive than other browsers'). STEP 2 -- Issue/refresh the CSRF token AFTER session regeneration. If login regenerates the session id (good practice, prevents session fixation), make sure the CSRF token is (re)generated and the form rendered AFTER the new session exists -- never bind the form to a token from a session that login then throws away. WHY: otherwise the token in the rendered form belongs to the pre-login session and won't match after regeneration -> "Invalid CSRF token." STEP 3 -- Use a per-session (or refresh-tolerant) token for the login form. Avoid aggressive PER-REQUEST rotation on the login flow specifically. WHY: per-request rotation is what breaks the Back button and multiple tabs -- an older page holds a token the server already replaced. A per-session token tolerates Back/multi-tab. STEP 4 -- Handle a login token mismatch GRACEFULLY. If a login submission arrives with a stale token, re-render the login page with a FRESH token (and a gentle "please try again") instead of a hard 403 error page. WHY: turns the rare residual mismatch into a transparent retry, so the user never sees the scary error. WHY EACH FIX ADDRESSES STALENESS, NOT PROTECTION-WEAKENING: - None of these disables the token check, exempts the endpoint, or loosens SameSite. They fix WHY the token was stale (caching, session lifecycle, over-aggressive rotation) so a LEGITIMATE submit carries a matching token. - A real CSRF attacker never had a valid token at all; these changes don't help them -- they still can't read or guess the token. The protection is fully intact; only the false-positive on legitimate users is removed. WHY IT APPEARED IN FIREFOX: - Firefox's bfcache aggressively restores the previous page (including the login form and its stale token) when navigating, more so than other browsers' defaults. So the stale-token condition surfaces there first. Testing in Chrome/Edge/Safari may differ -- but Step 1 (no-store) fixes it consistently across all of them. WHAT NOT TO DO: - Do NOT "fix" it by disabling CSRF on login, exempting the route, or setting SameSite=None. That trades a usability annoyance for a real vulnerability. Fix the staleness cause instead.