Skip to content
UniCircle
MediumConceptualWeb security (CSRF)

What is CSRF, and how do SameSite cookies and anti-CSRF tokens stop it?

Question CYB-WEB-008

Explain cross-site request forgery (CSRF) conceptually. Why does it work, which requests are at risk, and what defences should a web application use?

Show the explanation

The idea. Browsers automatically attach a site's cookies to requests sent to that site, even when another website triggered the request. If a bank keeps users logged in with a session cookie and accepts a state-changing request (such as "transfer money" or "change e-mail") without any further proof, a page on a different site could cause the victim's browser to send that request. The bank would see a valid cookie and carry it out. That is cross-site request forgery: the attacker borrows the victim's authenticated session to make them perform an action they did not intend.

What makes an application vulnerable

  • It uses ambient credentials, ones the browser sends automatically: cookies, HTTP Basic auth, sometimes client certificates.
  • State-changing actions can be triggered by a request whose content the attacker can predict.
  • There is no check that the request came from the application's own pages.

APIs authenticated with a token in an Authorization header that JavaScript must add explicitly are generally not exposed in the same way. Cookie-based sessions are the classic risk.

Defences

  1. SameSite cookies. Set-Cookie: session=...; SameSite=Lax; Secure; HttpOnly. With Lax, the cookie is not sent on cross-site sub-requests or cross-site POSTs, but it is sent on top-level navigations that use safe methods such as clicking a link. Strict never sends it cross-site. Many browsers now treat cookies without the attribute as Lax, but set it explicitly.
  2. Anti-CSRF tokens (synchronizer tokens). The server puts an unpredictable token, tied to the user's session, into each form or page, and rejects state-changing requests without the correct token. Another site cannot read it, because the same-origin policy prevents that. Most frameworks (Django, Rails, Spring Security, Laravel) have this built in. Keep it enabled.
  3. Check the Origin or Referer header on state-changing requests, and accept only your own origins.
  4. Use the right HTTP methods. GET must never change state. Use POST, PUT or DELETE for changes. This is what makes SameSite=Lax effective.
  5. Re-authenticate for sensitive actions (password change, payments) with the current password, OTP or MFA.
  6. CORS is not a CSRF defence. It controls who can read responses, not who can send requests. Never configure it to reflect arbitrary origins together with credentials.

CSRF vs XSS: CSRF tricks the browser into sending a request. XSS runs script inside the site. An XSS flaw defeats CSRF tokens, because the script can read them, so the XSS defences matter too.

Original UniCircle question. Last reviewed 22 Oct 2026.