What Is Cross-Site Request Forgery (CSRF)?
CSRF tricks a logged-in user's browser into sending an unwanted request. Learn the concept and defences: anti-CSRF tokens, SameSite cookies and origin checks.
Cross-site request forgery is one of the sneakier web attacks because it never has to break into your site at all — it simply borrows your logged-in users' authority and uses it against them. In plain terms, CSRF tricks a victim's browser into sending a request the user never intended to a site where they are already logged in, so the action runs with the victim's credentials. A single click on a malicious page, or even just loading it, can be enough to change a setting, send a message, or perform a transaction as the victim. This guide explains the concept, why it works, and the layered, well-established defences that stop it — all from a site owner's defensive perspective, with no working attack code.
It is a core part of how to protect your website from common attacks, and several of its defences overlap with how to secure cookies with HttpOnly, Secure and SameSite.
What CSRF is, in plain terms
Cross-site request forgery sits on the OWASP radar as a long-standing web risk. The name unpacks neatly: it is a forged request that originates cross-site (from a site other than yours) and abuses an authenticated session.
Here is the scenario, conceptually. A user logs into a site they trust — their bank, a web app, a content management system — and a session is established, tracked by a cookie in their browser. While that session is still active, the user visits a different, malicious (or compromised) page in another tab. That page quietly instructs the user's browser to send a request to the trusted site: perhaps to change the account email address. Because the browser automatically attaches the trusted site's cookies to any request bound for that site — regardless of which page triggered the request — the trusted site sees a perfectly authenticated request and carries out the action. The user has no idea anything happened.
The essential insight is that CSRF exploits the victim's authority, not a flaw in your code's logic. Your endpoint did exactly what it was told by what looked like a legitimate, authenticated user. The attack is making the browser tell it to do something the user never chose.
Why it works: ambient authority
The root cause is what is sometimes called ambient authority — the browser's helpful habit of automatically including cookies (and other credentials) with every request to a given site. That behaviour is what keeps you logged in as you click around a site. But the browser does not distinguish between a request you initiated by clicking a button on the real site and a request initiated by a hidden element on a malicious page. To the server, both arrive with the same valid session cookie.
So CSRF needs three things to line up: the victim is authenticated to the target site; the target accepts a state-changing request based on the session cookie alone; and the attacker can get the victim's browser to issue that request from elsewhere. Every defence below works by breaking one of those links — most often by requiring something the attacker cannot supply, or by stopping the cookie from being sent cross-site.
CSRF versus XSS: a crucial distinction
It is worth separating CSRF from cross-site scripting (XSS), because they are often confused.
- XSS runs the attacker's code inside your site. Once script executes on your origin, it can read cookies and tokens and act with full access to the page.
- CSRF runs no code on your site. It only causes the victim's browser to send a legitimate-looking request from another origin.
The distinction matters for two reasons. First, the defences differ. Second, and importantly, XSS can defeat CSRF defences: if an attacker can run script on your origin, they can usually read your anti-CSRF tokens and craft a valid request. That is why preventing XSS is part of protecting against CSRF too — a point the XSS guide develops in detail. Strong CSRF protection assumes you have kept XSS out.
Defence 1: the synchronizer token pattern
The classic, robust defence is the synchronizer token pattern, usually called an anti-CSRF token. It works like this:
- The server generates a secret, unpredictable token and associates it with the user's session.
- That token is embedded in the page — typically as a hidden field in forms, or made available to the site's own JavaScript.
- Every state-changing request must include the token.
- The server rejects any such request that lacks a valid token for the session.
Why does this stop CSRF? Because of the same-origin policy, a malicious page on another origin cannot read the token out of your pages, and being unpredictable, it cannot be guessed. So while the attacker can still make the browser send a request, they cannot make it carry a valid token — and the server refuses it. The synchronizer token is widely regarded as the most reliable single CSRF defence, and it is exactly what most frameworks implement for you.
Defence 2: SameSite cookies
A powerful, modern layer is the SameSite cookie attribute, which directly addresses the ambient-authority problem by telling the browser not to send a cookie on cross-site requests in many cases.
SameSite=Strict— the cookie is sent only when the request originates from the same site. The strongest setting, though it can affect legitimate cross-site navigation (for example, following a link into your site may not carry the session on the first request).SameSite=Lax— the cookie is sent on same-site requests and on top-level navigations using safe methods, but withheld from cross-site sub-requests and cross-site state-changing requests. This is a sensible default and is now the default in modern browsers when no attribute is set.SameSite=None— the cookie is sent on all cross-site requests and must be paired withSecure; only use it when you genuinely need cross-site cookie behaviour.
Setting session cookies to Lax or Strict neutralises a large class of CSRF because the attacker's cross-site request simply arrives without the session cookie, so it is not authenticated. The catch: behaviour varies somewhat across browsers, request types and edge cases, so SameSite is best treated as a strong layer alongside tokens, not a sole replacement. The full cookie guidance is in how to secure cookies with HttpOnly, Secure and SameSite.
Defence 3: the double-submit cookie pattern
When server-side session storage of a token is inconvenient (for example, in some stateless API designs), the double-submit cookie pattern is an alternative. The server sends a random token in a cookie, and the site's own code also sends the same token as a request header or form field. The server compares the two: a genuine same-site request can read the cookie and echo it back, whereas a cross-site attacker cannot read the cookie value to replicate it in the header.
Double-submit is simpler to scale than the synchronizer pattern but is generally considered somewhat weaker, and it must be implemented carefully (for instance, binding the token properly and combining it with other checks) to avoid subtle bypasses. Where you can use the synchronizer token, prefer it; use double-submit when statelessness genuinely requires it.
Defence 4: checking Origin and Referer
Browsers attach an Origin header (and often a Referer header) indicating where a request came from. The server can verify that state-changing requests originate from your own site and reject those that do not. This is a useful additional check, especially for APIs.
Treat it as a supporting layer, however, not the sole defence: the Referer header can be absent for privacy reasons, and relying on header checks alone is more fragile than a token. Combined with tokens and SameSite cookies, though, an Origin check on sensitive endpoints is a cheap, sensible reinforcement.
Defence 5: re-authentication for sensitive actions
For the most consequential operations — changing a password or email, large transactions, deleting an account — requiring the user to re-enter their password, confirm via a second factor, or pass a step-up authentication adds a barrier a forged request cannot clear. Even if every other layer somehow failed, the attacker does not possess the victim's password or second factor. Reserve this for genuinely sensitive actions so it does not harm everyday usability, but use it where the stakes justify the friction.
Defence strength at a glance
| Defence | How it stops CSRF | Strength |
|---|---|---|
| Synchronizer (anti-CSRF) token | Requires a secret token the cross-site attacker cannot read or guess | Strong — the canonical primary defence |
| SameSite=Strict/Lax cookies | Browser withholds the session cookie on cross-site requests | Strong layer; combine with tokens |
| Double-submit cookie | Compares a cookie value echoed back in a header/field | Moderate; for stateless designs, implement carefully |
| Origin / Referer check | Rejects requests not originating from your site | Supporting layer; headers can be missing |
| Re-authentication / step-up | Demands a credential a forged request lacks | Strong for sensitive actions; use selectively |
| GET has no side effects | Removes the easiest-to-trigger attack vector | Foundational design rule |
Use your framework's built-in protection
Here is the most practical advice in this article: do not build CSRF protection from scratch. Virtually every mature web framework — across the popular server-side ecosystems — ships built-in CSRF protection, typically an implementation of the synchronizer token pattern that integrates with its form handling, plus sensible cookie defaults. The right move is almost always to enable and correctly configure that built-in protection rather than hand-rolling your own, which is easy to get subtly wrong.
A common pitfall is disabling the framework's CSRF protection to make something work — for example, to get an API endpoint or a third-party callback functioning — and forgetting to re-enable or properly replace it. If you must exempt an endpoint, do so deliberately and ensure it is protected another way (an API using token-based auth in a header, for instance, is generally not cookie-driven and so not classically CSRF-vulnerable, but verify that reasoning for your case).
A foundational rule: keep GET safe
One design principle prevents a whole category of trouble: never let a GET request perform a state-changing action. GET requests are trivially easy to trigger from another site (a simple image or link can do it) and are conventionally expected to be safe and side-effect-free. Reserve GET for reading; require POST, PUT, PATCH or DELETE — protected by tokens — for anything that changes state. This both aligns with HTTP conventions and removes the easiest CSRF vector.
How site owners can sanity-check CSRF posture
You cannot fully "scan" for CSRF from the outside the way you check a header, but you can sanity-check your posture:
- Confirm your framework's CSRF protection is enabled and not globally disabled.
- Inspect your session cookies'
SameSiteattribute — DevTools (Application/Storage → Cookies) orcurl -Ishows theSet-Cookieflags; aim forLaxorStrict. - Verify that state-changing endpoints reject requests without a valid token and do not respond to GET.
- Check that sensitive actions require re-authentication.
Broader audits help with the cookie side: StackOptic, for example, surfaces cookie flags and security headers as part of a wider report, so you can confirm SameSite and related settings alongside performance and SEO — see how to read a website's HTTP headers for reading those raw signals.
A quick CSRF checklist
- Enable your framework's built-in CSRF protection (synchronizer tokens) and keep it on.
- Set session cookies to
SameSite=LaxorStrict(andSecure, andHttpOnly). - Require a valid anti-CSRF token on every state-changing request.
- Never perform state changes via GET; use POST/PUT/PATCH/DELETE.
- Add
Origin/Refererchecks on sensitive endpoints as a supporting layer. - Require re-authentication for high-impact actions.
- Remember that preventing XSS is part of protecting CSRF tokens.
Go deeper
- The defence-in-depth picture: how to protect your website from common attacks.
- The cookie attributes that matter: how to secure cookies with HttpOnly, Secure and SameSite.
- The attack that can defeat CSRF defences: what is cross-site scripting (XSS) and how to prevent it.
- The related UI attack: what is clickjacking and how to prevent it.
Want your cookie flags and security headers checked in one place? Analyse any URL with StackOptic — security, performance and SEO in one free report.
Frequently asked questions
What is cross-site request forgery (CSRF)?
Cross-site request forgery, often abbreviated CSRF, is an attack that causes a logged-in user's browser to send a request the user did not intend to a site where they are authenticated. Because the browser automatically includes that site's session cookies, the request appears to come from the legitimate user, so a state-changing action — changing an email address, transferring funds, altering settings — is carried out with the victim's privileges, without their knowledge or consent.
How is CSRF different from XSS?
They are distinct. Cross-site scripting (XSS) injects and runs malicious script inside your site, giving the attacker direct access to the page, cookies and tokens. Cross-site request forgery does not run code on your site at all; it merely tricks the victim's browser into sending a legitimate-looking request from elsewhere. XSS is generally the more powerful attack, and notably it can defeat many CSRF defences, which is one reason preventing XSS matters for CSRF protection too.
What is an anti-CSRF token?
An anti-CSRF token is a secret, unpredictable value the server generates and ties to the user's session, then embeds in forms or pages. When the browser submits a state-changing request, it must include this token, and the server rejects any request without a valid one. Because an attacker on a different site cannot read the token (the same-origin policy prevents it) or guess it, they cannot forge a request that passes the check. This is the synchronizer token pattern.
Do SameSite cookies prevent CSRF?
SameSite cookies are a strong, modern layer of CSRF defence, but they are best combined with tokens rather than relied on alone. SameSite=Lax or Strict tells the browser not to send your cookies on many cross-site requests, which neutralises a large class of CSRF. However, behaviour can vary by browser, request type and edge cases, so the robust approach is defence in depth: SameSite cookies plus anti-CSRF tokens plus Origin checks on sensitive endpoints.
Which requests need CSRF protection?
Any request that changes state — creating, updating or deleting data, changing settings, transferring value, or performing an action — needs CSRF protection. Safe, read-only requests that have no side effects, such as a properly implemented GET that only fetches data, do not. A key design rule follows from this: never let a GET request perform a state-changing action, because GET requests are the easiest for an attacker to trigger from another site.
Analyse any website with StackOptic
Get the full technology stack, performance, security and SEO report in seconds — free.
Analyse a websiteRelated articles
How to Check a Website for Malware
A practical guide to checking any website for malware: the free external scanners to use, the signs of infection, server-side checks, and what to do next.
What Is a Data Breach and How to Respond
A plain-English guide to data breaches: what counts as one, the common causes, a step-by-step incident-response plan, the GDPR 72-hour rule, and prevention.
How to Protect Your Website from Bots and Scrapers
Not all bots are bad. Tell good crawlers from abusive scrapers, spot the signals of bot traffic, and layer rate limiting, CAPTCHA, a WAF and bot management.