CSRF (Cross-Site Request Forgery):Attacks & Defenses
SameSite cookies, and verifying the Origin header for state-changing requests.CSRF abuses the browser's own helpfulness: it sends your session cookie with every request to a site, no matter who triggered the request. That lets a malicious page act on your behalf without ever seeing your data. This guide explains how CSRF works, how it differs from XSS, and how to defend against it. It pairs with our guides on XSS and secure cookies.
What Is CSRF?
CSRF (also called XSRF or a 'confused deputy' attack) happens when an attacker causes a victim's browser to send a request to a site where the victim is already logged in. Because the browser automatically includes the victim's session cookie, the target site sees a fully authenticated request and processes it: even though the victim never intended to send it. The attacker cannot read the response; they can only trigger the action.
How Does a CSRF Attack Work?
Suppose a banking app changes the account email via a simple form POST. An attacker hosts a page that auto-submits that request. When a logged-in victim visits the malicious page, their browser sends the request with their session cookie attached:
<!-- On attacker.tld: auto-submits to the victim's bank -->
<form action="https://bank.example/email" method="POST">
<input name="email" value="attacker@evil.tld">
</form>
<script>document.forms[0].submit()</script>
The bank receives an authenticated request to change the email and, with no CSRF defense, complies. The attacker now controls password resets for the account.
CSRF vs XSS: What Is the Difference?
| Dimension | CSRF | XSS |
|---|---|---|
| What it abuses | Automatic cookie sending by the browser | Untrusted data executed as script |
| Attacker can read response? | No, only trigger the action | Yes, full access to the page |
| Runs code in your origin? | No, request comes from another site | Yes, script runs in your origin |
| Primary defense | CSRF tokens + SameSite cookies | Output encoding + CSP |
An important relationship: XSS defeats CSRF protection. If an attacker has script execution via XSS, they can read the CSRF token and forge valid requests. That is why XSS is the higher priority to fix. See our XSS guide for that side of the story.
How Do You Prevent CSRF?
1. Anti-CSRF Tokens (Primary Defense)
Issue a unique, unpredictable token per session (or per request) and require it on every state-changing request. The token is delivered in the page (not as a readable cookie) and verified server-side. Because a cross-site attacker cannot read the token, they cannot forge a valid request. This is the synchronizer token pattern.
2. SameSite Cookies
Setting SameSite=Lax or SameSite=Strict on session cookies tells the browser not to send them on cross-site requests, which blocks most CSRF at the browser level. Lax is a sensible default; Strict is stronger but can break legitimate cross-site navigation. Treat SameSite as a strong baseline, not a complete replacement for tokens. We cover the cookie flags in detail in Session Management and Secure Cookies.
3. Verify Origin and Referer Headers
For state-changing requests, check that the Origin (or Referer) header matches your site. This is a useful defense-in-depth layer, since the browser sets these headers and a cross-site page cannot spoof its own origin.
4. Require Re-Authentication for Sensitive Actions
For high-value operations: changing a password, email, or making a payment: prompt for the password again or a second factor. Even if other defenses fail, the attacker cannot supply the credential.
CSRF Prevention Checklist
- Use anti-CSRF tokens on all state-changing requests (POST, PUT, PATCH, DELETE)
- Set SameSite=Lax or Strict on session cookies
- Verify the Origin or Referer header for sensitive requests
- Never use GET for actions that change state
- Require re-authentication or MFA for high-value actions
- Use your framework's built-in CSRF protection rather than rolling your own
- Fix XSS first: it bypasses every CSRF control