RoastMyOpsec

Safety

CSRF Tokens vs SameSite for State-Changing Forms

April 23, 2023

CSRF tokens vs SameSite is a pairing, not an either-or contest. SameSite on the session cookie reduces how often a foreign site can attach credentials to a request. Anti-CSRF tokens (or Fetch metadata / Origin checks) still belong on state-changing forms because SameSite=Lax allows some top-level GETs, cookies can be SameSite=None for embeds, and not every client is a modern browser. RoastMyOpsec's vault CSRF check is a heuristic on landing HTML — form tags and token-ish field names — not a proof that your server validates anything.

The practical difference

SameSite is a cookie attribute. It changes when the browser includes the cookie on cross-site requests. It does nothing if the action does not need that cookie, or if the cookie is None.

A CSRF token is an unguessable value bound to the session that the server demands on POST/PUT/DELETE. Origin and Referer checks are a complementary server rule: reject state changes whose Origin is not you.

How to choose based on the form

Read-only search GET forms are usually not CSRF-critical. Password change, transfer, delete, and email-update POSTs are. Cookie-based apps should set SameSite=Lax or Strict on the session cookie and still require a token or Origin check on those POSTs.

ControlStopsDoes not stopTakeaway
SameSite=LaxMany cross-site POSTs with cookiesSome cross-site top-level GETs; None cookiesNecessary default, not sufficient alone
SameSite=StrictMore inbound cookie ridingLogged-out CSRF of unauthenticated actionsBest for consoles; worse for inbound links
Synchronizer / double-submit tokenForged POSTs that lack the secretXSS that can read the tokenStill need HttpOnly sessions and CSP
Origin / Referer checkCross-site POSTs with a clear OriginMissing Origin edge casesCheap extra belt on the server

When SameSite-only fails

SPA frameworks that put mutations on GET, or that use SameSite=None for a widget, re-open the old problem. Tokens and Origin checks are how you keep those designs honest.

If there are no forms on the landing page, a public scan may look clean. Confirm login and settings routes on a host you own.

Common mistakes

The first mistake is SameSite=Lax on the cookie and no server check on POST.

The second mistake is a CSRF token in the page that the API never validates.

The third mistake is protecting /login and leaving /api/delete wide open.

Free audit the URL you own

RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.

Free audit now

FAQ

Is SameSite enough to stop CSRF?
It is a strong reduction for cookie-based sites on modern browsers. It is not enough by itself for every cookie mode, every method, or every client. Keep tokens or Origin checks on state changes.
Do JSON APIs need CSRF tokens?
Cookie-authenticated JSON APIs still need a CSRF strategy (token, custom header that CORS would not send from a foreign site, or SameSite plus Origin). Bearer tokens in Authorization are a different model.
How does RoastMyOpsec check CSRF?
It parses public landing HTML for forms and common token field names. Heuristic only — no forged submissions.

Sources

Related guides