QuestionsNetworking/Security

CSRF: how it works and how to stop it

Web VulnerabilitiesMediumNetworking/Security

Explain a cross-site request forgery attack step by step, and the modern defenses. How does SameSite change the picture?

What it tests

Understanding CSRF as an abuse of ambient cookie authority, and why SameSite + tokens together are the answer.

Approach & answer

CSRF (cross-site request forgery) tricks a logged-in user's browser into sending a state-changing request to a site they're authenticated with, WITHOUT the attacker ever seeing the response. It exploits a specific fact: the browser attaches your cookies to a request based on the DESTINATION, regardless of which site initiated it. So the flow is: you're logged into bank.com (you have a session cookie). You visit evil.com, which contains a hidden auto-submitting form that POSTs to bank.com/transfer with attacker-chosen params. Your browser sends that POST and — because it's going to bank.com — automatically includes your bank.com session cookie. The server sees a valid, authenticated request and executes the transfer. The attacker doesn't need to read anything (the same-origin policy still blocks that); they just need the side effect. Note CSRF only works against actions authenticated by AMBIENT credentials the browser sends automatically — cookies (and HTTP Basic/NTLM). It does NOT work against auth that requires the app to actively attach a token, like an Authorization: Bearer header from JS, because evil.com's request can't add that header. Defenses, layered: (1) SameSite cookies — SameSite=Lax (now the browser default) stops the cookie from being sent on cross-site subrequests like that hidden POST, which neutralizes the classic attack; Strict is even tighter. This is the biggest single improvement and is why CSRF is less pervasive than it once was. (2) Anti-CSRF TOKENS — the server embeds an unpredictable, per-session (or per-request) token in forms/pages; legitimate requests echo it back (in a hidden field or header), and evil.com can't read or guess it (SOP blocks reading the page). The synchronizer-token and double-submit-cookie patterns implement this. (3) Verifying Origin/Referer headers on state-changing requests as a secondary check. Don't rely on SameSite alone (older browsers, and some cross-site flows legitimately need None), and never assume 'it's a POST so it's safe' — POSTs are exactly what CSRF targets. The robust posture: SameSite cookies as the baseline PLUS anti-CSRF tokens for state-changing endpoints.

Use this technique when

Securing state-changing endpoints; explaining why a POST needs a token; choosing SameSite settings.

Code

<!-- The attack: evil.com auto-submits a request to a site you're logged into -->
<form action="https://bank.com/transfer" method="POST" id="f">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('f').submit();</script>
<!-- Browser attaches YOUR bank.com cookie because the request GOES TO bank.com.
     Attacker never reads the response (SOP blocks that) — the side effect is enough. -->

<!-- Defenses (layered) -->
<!-- 1. Cookie: sid=...; SameSite=Lax  -> not sent on this cross-site POST -->
<!-- 2. Anti-CSRF token the attacker can't read or guess: -->
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="{{ per-session unpredictable token }}">
  ...
</form>
<!-- 3. Server also checks Origin/Referer on state-changing requests. -->

References