SameSite Cookies, In Depth
The SameSite cookie attribute controls whether a cookie is sent on cross-site requests, making
it a frontline defense against CSRF. Its three values trade off
security against usability, and a browser default change made Lax the baseline for most cookies.
Understanding the distinctions is key to both securing and not accidentally breaking your app.
Strict, Lax, or None?#
| Value | Sent cross-site? | Trade-off |
|---|---|---|
Strict | Never | Most secure; can log users out via external links |
Lax | Only top-level GET navigations | Balanced; the modern default |
None | Always (requires Secure) | For legitimate cross-site cookies (e.g. embeds) |
Strict is ideal for the most sensitive cookies where you never want cross-site delivery.
Lax — now applied by default when no attribute is set — blocks the classic cross-site POST while
still letting a user who clicks a link to your site arrive logged in. None must be paired with
Secure and is for cookies that genuinely need to travel cross-site.
What did the Lax-by-default change do?#
Browsers now treat cookies with no SameSite attribute as Lax. This retroactively protected a
huge number of sites from basic CSRF — but it also means a cookie that truly needs cross-site use
must now explicitly declare SameSite=None; Secure, or it silently stops working in embedded
contexts.
Where SameSite falls short#
SameSite is powerful but not a complete CSRF solution:
- Some GET-based state changes can still be triggered.
- Subdomains are same-site, so it does not isolate
evil.example.comfromapp.example.com. - Older browsers may ignore it.
SameSite is the modern core of cookie security and CSRF defense. More at the Web Security hub.
Frequently asked questions#
What is the difference between SameSite Strict, Lax, and None?
Strict never sends the cookie on any cross-site request, even top-level navigation — most secure, but it can log users out when arriving from external links. Lax sends it only on top-level GET navigations, a balance now used as the browser default. None sends it on all cross-site requests but requires the Secure attribute.
Does SameSite fully replace CSRF tokens?
Not entirely. SameSite=Lax blocks the classic cross-site POST, covering many cases, but gaps remain: some GET-based state changes, complex subdomain or multi-site setups, and older browsers. Treat SameSite as a strong default layer and add anti-CSRF tokens for sensitive state-changing actions.