Skip to content
العربية

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.

Estimated time
25 min
Level
Intermediate
Your progress in this track0%

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:

the real 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:

attacker.html
<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=Lax tells the browser not to attach the cookie on most cross-site requests; SameSite=Strict withholds it on all of them.
  • Keep state changes off GET. A GET should only read. If it changes something, a simple link or image can trigger it — and SameSite=Lax still allows the cookie on a top-level GET navigation.
safe.js
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; Secure

XSS 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.

Review questionA site requires a CSRF token on POST /transfer, but GET /transfer?to=... also moves money and checks no token. Is the site safe from CSRF?

Labs

  • A request from another site

    EasyBrowser lab

    Build an attacker page that sends a forged request changing the leader’s recovery email to yours, and deliver it to him.

  • A token on the front door only

    MediumBrowser lab

    Change the leader’s recovery email to yours despite the token on the POST request.

  • A gap in the last line of defense

    HardBrowser lab

    Change the leader’s recovery email to yours despite the SameSite=Lax protection.