Quiz
Eight scenarios designed to surface where your CSRF instincts are sharp and where they need a refresh. Each item lists the endpoint, auth model, and asks for the right defence. Answers explain the reasoning.
Eight CSRF questions, with reasoning
EXAMPLE
# ============================================================ # Q1) Cookie-session web app. POST /account/email mutates email. # ============================================================ # ANSWER: # - VerifyCsrfToken middleware on the route (or the framework default 'web' group) # - @csrf hidden field in the form # - SameSite=Lax + Secure on the session cookie # - Origin header check as belt-and-braces # ============================================================ # Q2) Bearer-token API. POST /api/orders. No cookies anywhere. # ============================================================ # ANSWER: no CSRF token required. Browsers will not attach the Authorization # header on a cross-origin form submission, and your endpoint rejects requests # without it. Belt-and-braces: a custom required header. # ============================================================ # Q3) SPA at app.example.com, API at api.example.com (same parent). # Auth via session cookie set on .example.com. # ============================================================ # ANSWER: # - Double-submit token: server sets an XSRF-TOKEN cookie, SPA echoes it back # as X-XSRF-TOKEN header on each request # - SameSite=Lax on the session cookie (Strict will break cross-subdomain # navigations) # - CORS allowed_origins = exact list, supports_credentials = true # ============================================================ # Q4) GET /logout terminates the session. # ============================================================ # ANSWER: this IS the bug. GET requests can be triggered cross-origin via # <img>, <link>, redirects. Even SameSite=Lax does not block GETs on top-level # navigations. # Fix: change to POST, attach the token, OR add a confirmation step. # ============================================================ # Q5) Stripe webhook posts to /webhooks/stripe with a signature header. # ============================================================ # ANSWER: # - EXEMPT the route from CSRF middleware (no cookie auth involved) # - VERIFY the signature header using Stripe's documented constant-time compare # - VALIDATE the timestamp window (default 5 minutes) # Treat the signature as the auth boundary; a CSRF token here would be wrong. # ============================================================ # Q6) Admin panel behind a corporate VPN. # ============================================================ # ANSWER: # - Still ship the CSRF token. VPN does NOT prevent CSRF; an admin with a tab # open on a hostile site is still vulnerable. # - Use SameSite=Strict on admin cookies (not Lax) # - Consider mTLS for /admin routes # - Keep separate cookies/sessions for admin and customer-facing apps # ============================================================ # Q7) Multi-step form upload (multipart/form-data with files). # ============================================================ # ANSWER: same CSRF defence. Encoding does not change the threat model — the # browser attaches the session cookie regardless. The form just needs the # token like any other. # ============================================================ # Q8) Public form anyone can submit (contact form, no auth). # ============================================================ # ANSWER: no CSRF defence applies — there is no authenticated user to forge as. # What DOES matter: # - Rate limit # - reCAPTCHA / hCaptcha # - HTML escape of incoming user text in any rendered output (XSS, not CSRF) # - Email-injection escape if the form sends email # ============================================================ # Bonus — what is the WORST defence? # ============================================================ # ANSWER: 'we require POST'. Forged POSTs from another origin work fine if the # session cookie travels with them (which it does, by default). # Scoring # 8 / 8 -> code review at speed # 5 / 8 -> revisit the csrf/summary lesson # < 5 -> read the framework docs for the auth model you ship
Why it matters
The CSRF decision rule that catches most bugs: "is auth attached automatically by the browser?". Cookie-auth -> yes -> need a token (or a custom required header). Bearer header -> no -> CSRF is structurally impossible. Mismatch in your code review thinking creates 80% of CSRF bugs.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…