CSRF
Cross-Site Request Forgery: an attack that tricks a logged-in user's browser into sending unwanted requests to a site where they're authenticated. Prevented with tokens.
What is CSRF?
In short
CSRF (Cross-Site Request Forgery) is a web attack where a malicious site tricks a victim's browser into sending an authenticated request to another site the victim is logged into, causing an action the victim never intended, such as transferring money or changing an email. Because the browser automatically attaches the victim's session cookie, the target site sees a valid request and the defense is to require a secret token the attacker cannot guess.
What CSRF actually is
CSRF abuses the fact that browsers automatically send cookies for a domain on every request to that domain, no matter who triggered the request. If you are logged into your bank at bank.com, your browser holds a session cookie. When any page in any tab makes a request to bank.com, the browser attaches that cookie for you.
An attacker exploits this by getting your browser to fire a request to bank.com while you are logged in. They do not steal your cookie and they cannot read the response. They only need the request to reach the server with your cookie attached, so the server treats it as a legitimate action from you.
The classic targets are state-changing endpoints: transfer money, change password, change account email, delete data, add an admin. Read-only pages are not the prize. CSRF is about forcing a write, not stealing data, which separates it from XSS.
How the attack works under the hood
The simplest version uses an HTML form or image tag on a page the victim visits. A hidden form with action set to https://bank.com/transfer and method POST can auto-submit with JavaScript the moment the page loads. The browser sends the POST to bank.com with the victim's cookie, and the transfer goes through.
GET-based endpoints are even easier to attack. An image tag like img src pointing to https://bank.com/transfer?to=attacker&amount=5000 fires a GET request with cookies attached as soon as the browser tries to load the image. This is one reason GET requests must never change server state.
The attacker never sees the bank's response because the same-origin policy blocks cross-origin reads. That does not matter to them. The damage is done the moment the server processes the forged write. The victim usually notices nothing.
Defenses and trade-offs
The standard defense is the synchronizer token pattern. The server generates a random secret token, embeds it in each form or sends it as a header value, and rejects any state-changing request that does not carry the matching token. The attacker's page cannot read this token because the same-origin policy blocks it, so they cannot forge a valid request.
A second layer is the SameSite cookie attribute. SameSite=Lax (the default in Chrome since 2020 and most modern browsers) stops cookies from being sent on cross-site POST requests and most cross-site sub-requests, which kills a large share of CSRF on its own. SameSite=Strict is tighter but breaks normal navigation from external links, so most sites use Lax plus tokens.
Servers should also check the Origin or Referer header on writes, since browsers set these and pages cannot forge them. The trade-off across all of this: tokens add per-request bookkeeping, SameSite can break legitimate cross-site flows like third-party embeds and some OAuth redirects, and APIs that authenticate with bearer tokens in an Authorization header instead of cookies are not vulnerable to CSRF at all because nothing is sent automatically.
A concrete real-world example
In 2008, a CSRF flaw in Gmail let an attacker add a mail filter to a victim's account. A victim who visited a malicious page while logged into Gmail had a forged request silently create a filter that forwarded all their email to the attacker. No password was stolen and the victim saw nothing.
The fix Google shipped is the same pattern everyone uses now: a per-session anti-CSRF token attached to state-changing requests and validated server side. Frameworks bake this in today. Django ships a csrf_token tag and middleware, Rails uses protect_from_forgery with a token in a meta tag, and Spring Security enables CSRF protection by default for browser sessions.
The practical rule that prevents most of these incidents: never let a GET request change state, require an unguessable token on every write, and set SameSite on your session cookie. Get those three right and CSRF stops being a realistic threat against a cookie-based session.
Where it is used in production
Django
Ships CSRF middleware on by default with a csrf_token template tag; rejects POST requests missing a valid token.
Ruby on Rails
protect_from_forgery is enabled by default and injects a per-session token into a meta tag for forms and AJAX.
Spring Security
Enables CSRF token validation by default for cookie-authenticated browser sessions in Java web apps.
Google Chrome
Made SameSite=Lax the default cookie behavior in 2020, blocking cookies on most cross-site writes and cutting CSRF exposure across the web.
Frequently asked questions
- What is the difference between CSRF and XSS?
- XSS injects and runs attacker JavaScript inside the victim's site, giving the attacker full read and write access to that page including cookies and tokens. CSRF runs no code on the target site; it just forces the browser to send a request and cannot read the response. A site fully protected against CSRF can still be wrecked by XSS, because XSS can read the CSRF token and forge valid requests.
- Why do CSRF tokens stop the attack if the attacker can still send requests?
- The attacker can send the request but cannot include a valid token. The token is a random secret the server put into your page, and the same-origin policy stops the attacker's page from reading it. Without the matching token the server rejects the write, so a forged request fails.
- Does SameSite cookies alone fully prevent CSRF?
- It blocks most CSRF, especially cross-site POSTs, and is a strong baseline. But it is not complete: same-site sub-domain attacks, older browsers, and certain top-level navigation cases can slip through SameSite=Lax. Best practice is SameSite plus anti-CSRF tokens, not one alone.
- Are REST APIs that use bearer tokens vulnerable to CSRF?
- No, not in the classic sense. CSRF depends on the browser automatically attaching credentials. A bearer token in an Authorization header is not sent automatically; your code has to add it, and an attacker's page cannot read or set it cross-origin. APIs that authenticate only via cookies remain vulnerable and still need CSRF protection.
- Why is it dangerous to change state with a GET request?
- GET requests are fired by browsers automatically through image tags, link prefetching, and other passive elements, so they are trivially forgeable by any page. They also get cached and logged. State-changing actions should use POST, PUT, PATCH, or DELETE combined with a token, never GET.
Learn CSRF hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
See also
Related glossary terms you might want to look up next.
XSS
Cross-Site Scripting: an attack where malicious scripts are injected into trusted websites. Prevented by sanitizing user input and setting Content-Security-Policy headers.
CORS
Cross-Origin Resource Sharing: a security mechanism that controls which domains can access your API. The browser enforces it; the server configures it.
Cookie
A small piece of data the server sends to the browser, which the browser stores and sends back with every subsequent request. Powers sessions, tracking, and preferences.
Throttling
Slowing down the rate of processing requests instead of rejecting them outright. The gentler cousin of rate limiting.
OAuth
An authorization framework that lets users grant third-party apps limited access to their accounts without sharing passwords. Powers 'Sign in with Google.'
JWT
JSON Web Token: a compact, self-contained token for transmitting claims between parties. The server can verify it without a database lookup.