How do SameSite cookies and CSRF tokens relate as defenses, and why is SameSite not a full replacement for Spring's CSRF protection?
answer
- SameSite: Strict/Lax/None on the cookie
- Lax still sends on top-level GET navigation
- same-site != same-origin (sibling subdomains)
- browser-enforced, not guaranteed
- defense in depth: SameSite + CSRF token
basics
~20 sSameSite=Lax/Strict tells the browser not to send the cookie on cross-site requests, blocking most CSRF at the cookie layer. But it's browser-dependent, Lax still allows top-level GET navigations, and coverage varies, so keep Spring's CSRF token as defense in depth.
solid answer
~50 s**SameSite** is a cookie attribute controlling whether the browser attaches the cookie on **cross-site** requests: `Strict` never sends cross-site, `Lax` sends only on top-level navigations with safe methods, `None` always sends (requires `Secure`). Setting `SameSite=Lax` (or `Strict`) on the **session/auth cookie** removes the ambient-credential condition CSRF depends on, so it's a strong first line. But it's **not a full replacement** for token-based CSRF protection: it relies on correct, up-to-date browser behavior (older/edge clients may ignore it); `Lax` still permits **cross-site top-level GET navigations**, so GET-based state changes stay exposed; and browsers may treat sibling subdomains as same-site, so it doesn't cover intra-domain attacks. Spring doesn't set SameSite via the CsrfFilter — you configure it on the session cookie (`server.servlet.session.cookie.same-site=lax` or a `DefaultCookieSerializer`). Best practice is **defense in depth**: SameSite cookies **and** Spring's synchronizer/double-submit token, plus never mutating on GET.
code
java · 10 lines// application.properties baseline for the auth/session cookie
// server.servlet.session.cookie.same-site=lax
// server.servlet.session.cookie.secure=true
// server.servlet.session.cookie.http-only=true
@Bean
CookieSameSiteSupplier applicationCookieSameSite() {
// Applies SameSite=Lax to Spring-managed cookies; keep Spring CSRF enabled too
return CookieSameSiteSupplier.ofLax();
}go deeper
Know SameSite makes browsers stop sending cookies cross-site, mitigating CSRF.
Distinguish Strict/Lax/None and know Spring sets it on the cookie, not the CsrfFilter.
Explain the gaps (Lax GET, browser dependence) and argue for layering SameSite with CSRF tokens.
Set org-wide policy: baseline cookie flags, keep token-based CSRF, forbid GET mutations, and reason about same-site vs same-origin and SameSite=None exposure.
## SameSite: what it does **`SameSite`** is an attribute on a `Set-Cookie` header instructing the browser when to include the cookie on requests initiated from another site: - **`Strict`** — the cookie is **never** sent on any cross-site request, including top-level navigations. Strongest, but breaks flows like following an inbound link into an authenticated area (you appear logged out). - **`Lax`** — the cookie **is** sent on **top-level navigations using safe methods** (a user clicking a link, GET), but **not** on cross-site subresource requests, iframes, or cross-site `POST`. This is the modern browser default when `SameSite` is unspecified. - **`None`** — sent on all cross-site requests; **must** be paired with `Secure` (HTTPS). Needed for legitimate cross-site cookie use. Because CSRF depends on the browser **auto-attaching the auth cookie** on an attacker-initiated request, `Lax`/`Strict` on that cookie neutralizes the classic form-POST CSRF: the cookie simply isn't sent, so the forged request is unauthenticated. ## Why it is not a complete replacement 1. **Client dependence.** SameSite is enforced by the browser. Very old browsers, non-browser HTTP clients, or buggy implementations may not honor it. Server-side token validation does not depend on client goodwill. 2. **`Lax` still allows top-level GET.** A cross-site top-level GET navigation *does* carry a Lax cookie. If any endpoint changes state on GET (a bug, but common), it remains exploitable. The CSRF token — combined with never mutating on GET — closes this. 3. **Same-site is not same-origin.** Browsers compute "site" by registrable domain (eTLD+1). `a.example.com` and `evil.example.com` are the **same site**, so a compromised or attacker-controlled **sibling subdomain** can issue "same-site" requests that still carry the cookie. Token-based CSRF (especially the session synchronizer token) still blocks these. 4. **Method/redirect nuances and legacy `None` needs.** Some integrations legitimately require `SameSite=None`, re-exposing the cookie; there the CSRF token is your remaining defense. ## Relationship to BREACH/token design SameSite protects at the **cookie transport** layer; CSRF tokens protect at the **request validation** layer; BREACH protection (`XorCsrfTokenRequestAttributeHandler`) protects the **token's confidentiality in responses**. They are orthogonal and complementary — a layered model. ## How to set SameSite in Spring Spring Security's `CsrfFilter` does **not** set SameSite. You control it on the cookie: - **Session cookie (Boot):** `server.servlet.session.cookie.same-site=lax` (and `secure=true`). - **Programmatically / Spring Session:** a `DefaultCookieSerializer` with `setSameSite("Lax")`. - **The CSRF cookie itself** (with `CookieCsrfTokenRepository`) can also carry SameSite via a customizer, but note it must remain readable by the SPA (`withHttpOnlyFalse`). ```java @Bean CookieSameSiteSupplier sameSiteLax() { return CookieSameSiteSupplier.ofLax(); // apply Lax to app-managed cookies } ``` ## Principal-level judgment - Treat SameSite as **hardening**, not the control of record. Regulatory/threat-model reviews should still require token-based CSRF for cookie-authenticated flows. - Enforce **`Secure` + `HttpOnly` + `SameSite=Lax`** on the auth cookie as a baseline, keep Spring CSRF enabled, and forbid state changes on GET in API design guidelines. - Reassess when adopting `SameSite=None` for cross-site embedding — that's precisely when the token matters most.
- Does SameSite=Strict let you safely disable Spring's CSRF token?Not for a robust posture. Strict is browser-enforced (old/edge clients may ignore it), 'same-site' includes sibling subdomains, and any GET-based mutation stays exposed. Keep the token as defense in depth.
- Why is 'same-site' weaker than 'same-origin' for CSRF reasoning?Browsers define site by registrable domain (eTLD+1), so a.example.com and evil.example.com are the same site and a compromised sibling subdomain can send cookie-bearing 'same-site' requests that SameSite=Lax/Strict won't block.
saying these in an interview costs you the question
- Claiming SameSite=Lax fully replaces CSRF tokens
- Assuming all clients honor SameSite
- Ignoring that Lax still sends cookies on cross-site top-level GET navigations
- Treating sibling subdomains as different sites for SameSite purposes