CSRF (Cross-Site Request Forgery)
How a malicious site makes your browser send a trusted, state-changing request to another site you are logged into, and how tokens and SameSite stop it.
- Track
- Web security
- Estimated time
- 25 min
- Level
- Intermediate
Before this lesson
CSRF is an attack that abuses something the browser does for you: it attaches your cookies to every request going to a site, no matter which page started the request. So if you are logged into a site and then open an attacker’s page, that page can quietly make your browser send a request to the site you are logged into — and the site, seeing your session cookie, treats it as you.
What is the vulnerability?
Say a control panel changes your recovery email with this request:
POST /settings HTTP/1.1
Host: panel.example
Cookie: session=abc123
[email protected]The attacker builds a page that makes your browser send the same request to panel.example:
<form action="https://panel.example/settings" method="POST">
<input type="hidden" name="email" value="[email protected]">
</form>
<script>document.forms[0].submit();</script>You open that page while logged in. The browser attaches your session cookie automatically, the panel sees a valid session, and it changes your recovery email to the attacker’s — the first step to taking over your account. You never clicked anything meaningful.
Why does it happen?
Cookies are Sent by the browser on every request to the matching site, with no action from the page or the user.: the browser sends them automatically. A server that decides “is this request allowed?” using the cookie alone cannot tell a request the user meant to make from one an attacker’s page made on their behalf. The two look identical.
How to prevent it
- A CSRF token. The server puts a random, per-session value in its own pages and requires it back on every state-changing request. An attacker on another site cannot read that value (the same-origin policy stops them), so they cannot include it.
- SameSite cookies.
SameSite=Laxtells the browser not to attach the cookie on most cross-site requests;SameSite=Strictwithholds it on all of them. - Keep state changes off GET. A
GETshould only read. If it changes something, a simple link or image can trigger it — andSameSite=Laxstill allows the cookie on a top-level GET navigation.
app.post('/settings', (req, res) => {
if (!req.session.user) return res.status(401).end();
if (req.body.csrf !== req.session.csrfToken) return res.status(403).end();
db.setRecoveryEmail(req.session.user, req.body.email);
res.end('updated');
});
// Set-Cookie: session=...; SameSite=Lax; HttpOnly; SecureXSS and CSRF are cousins but opposite: XSS runs the attacker’s code on the site, so it can read the token and defeats CSRF defenses; CSRF never runs code on the site, it only makes the browser send a request. Fix XSS first — a token cannot protect a page an attacker can script.
Labs
A request from another site
SolvedEasyBrowser lab
Build an attacker page that sends a forged request changing the leader’s recovery email to yours, and deliver it to him.
Enter the labLockedA token on the front door only
SolvedMediumBrowser lab
Change the leader’s recovery email to yours despite the token on the POST request.
Enter the labLockedA gap in the last line of defense
SolvedHardBrowser lab
Change the leader’s recovery email to yours despite the SameSite=Lax protection.
Enter the labLocked
