Arkendia Classrooms
Lesson 15 of 28 · 17 min

CSRF: cross-site request forgery

Imagine you are logged in to your bank in one tab. In another tab, you open a harmless-looking page. Without you noticing, that page makes your browser send a request to your bank, and your browser helpfully attaches your bank cookie. If the bank trusts the cookie alone, it executes the request as if you had made it. That is CSRF.

Lab only

Forcing another person’s browser to perform actions is an attack on that person and on the service. Test CSRF only between accounts and pages you control in your lab. If you ever find this kind of flaw on a real service within a bug bounty programme, you describe it in your report and demonstrate it only with your own test accounts.

Why it works

Browsers automatically include cookies in requests to a site, no matter which page triggered the request. This convenience is what makes login sessions work across tabs, but it also means a page on another site can cause your browser to send an authenticated request to the target site. The server sees a valid session cookie and has no easy way to tell whether the user actually intended the action.

Compare it to a signature on a cheque. The bank checks that the signature is valid, but not whether you meant to write that cheque. CSRF exploits the habit of authenticating the browser instead of confirming the intent.

The ingredients of a CSRF flaw

Three conditions must be present:

  1. A state-changing action worth forging: changing an email address, a password, a delivery address, transferring money, deleting an account, promoting a user.
  2. Cookie-based session handling: the browser sends the credentials automatically.
  3. Predictable request parameters: the attacker can work out every value required. If the request needs a secret value the attacker cannot know, the attack fails.

Here is a vulnerable endpoint, expressed as the request the browser sends when you change your email in a training application:

POST /account/change-email HTTP/1.1
Host: localhost:8080
Cookie: session=abc123
Content-Type: application/x-www-form-urlencoded

email=new-address@example.org

All the parameters are predictable: only one field, chosen by whoever builds the request. There is no secret in it. Any page that can make the user’s browser send this request while the session is active would change the account email, and from there a password reset (chapter 2) gives full takeover. This chain is a good example of why testers consider the combined effect of weaknesses rather than each one in isolation.

Dangerous GET requests

A particularly careless version uses a GET request for an action, such as /delete-account?id=5. A simple image reference on any page can trigger a GET request. The HTTP rule is that GET must be “safe”, meaning it should not change state. If an application changes data with GET, it fails twice: against HTTP conventions, and against CSRF. As a tester, note any state-changing GET in your inventory.

How testers check for CSRF

In your lab, with two test accounts, follow this approach.

  1. Pick a sensitive action from your inventory (change email, password, profile data).
  2. Capture the request in Burp and look at its parameters. Is there an unpredictable token in the form or a header? Is it tied to your session?
  3. Check the cookie’s SameSite attribute (chapter 2). With Strict or Lax, many cross-site requests will not carry the cookie, which already blocks the classic attack.
  4. Test the token’s validation in Repeater: does the request still succeed if you remove the token? If you use a token from your other test account? If you change the method from POST to GET? If you leave the value empty? A token that is present but not verified is no protection.
  5. Check other defences: does the server verify the Origin or Referer header, and does it require re-entering the password for critical actions?

Many training applications provide a ready-made demonstration: DVWA’s “CSRF” module lets you change the password of the logged-in user, and the Web Security Academy has labs that guide you through the different validation mistakes. Use them to see these behaviours first-hand.

Defences

Anti-CSRF tokens

The classic defence. When the server generates a form, it includes a random token tied to the user’s session. When the form is submitted, the server verifies that the token matches. A forged request from another site cannot include the right value, since the attacker’s page cannot read the target site’s pages (the same-origin policy again).

<!-- Hidden field in the form, generated per session -->
<input type="hidden" name="csrf_token" value="a-long-random-value">

The tokens must be unpredictable, checked on every state-changing request, and rejected when missing or wrong. Most mainstream frameworks offer this by default, so the typical flaw is a developer disabling or forgetting it for one route.

SameSite cookies

Setting SameSite=Lax or Strict on the session cookie tells the browser not to send it on most cross-site requests. Modern browsers apply a protective default in many cases, but you should set it explicitly rather than depend on defaults. It is an excellent second layer, not a substitute for tokens in sensitive applications.

Checking the origin

The server can verify that the Origin (or Referer) header of state-changing requests matches its own domain. This is a useful additional check.

Re-authentication and confirmation

For critical operations such as changing an email address or a password, require the current password or a second factor. This breaks the attack even when other defences fail, and it protects against other attacks too.

APIs using headers for credentials

If an API authenticates with a token that the application’s script adds manually to a header, instead of with a cookie, CSRF does not apply in the same way, since the browser does not add that header automatically. The risk then moves toward XSS, which could steal such a token. Each design trades one risk for another, which is why you should always consider the whole picture.

CSRF versus XSS

Students often confuse the two. A quick contrast:

XSSCSRF
What the attacker getsScript running inside the site’s pageA forged request sent by the victim’s browser
Can read responses?YesNo, only trigger actions
Exploits trust of…The user’s browser in the siteThe site in the user’s browser
Main defenceOutput encoding, CSPAnti-CSRF tokens, SameSite

Note also that an XSS flaw can defeat CSRF protection, since the injected script runs on the same origin and can read the token. This is why defences must be layered.

Tip

When assessing a finding, think of the impact chain. A CSRF on “change email” combined with a standard password reset is an account takeover. Writing the whole chain in the report makes the severity clear to the reader.

Your turn: evaluate an action’s CSRF protection

In your lab, choose the change-password or change-email feature. Capture the request in Burp, then fill this checklist in your notebook: Is there a token? Does the server validate it (test by removing it and by replaying it in Repeater with another account’s token)? What is the cookie’s SameSite value? Does the action ask for the current password? Conclude with a verdict and a recommendation.

See a solution

For DVWA’s low level, your table may look like this:

Action: change password (GET request with the new password in the URL)
Token: none
SameSite: not set on the session cookie
Current password required: no
Verdict: vulnerable to CSRF; also a state-changing GET, and the new password appears in URLs and logs
Recommendation: POST only, anti-CSRF token validated on the server,
                SameSite=Lax or Strict, ask for the current password

At the impossible level, you will see all of these defences in the source code. Compare the two as your model answer.

Key takeaways

  • CSRF makes the victim’s browser send an authenticated request the user did not intend, because cookies are attached automatically.
  • It needs a state-changing action, cookie-based sessions and predictable parameters.
  • State-changing GET requests are both a design error and a CSRF risk.
  • Test whether tokens are present and actually validated: missing, empty, reused or from another account.
  • Defend with anti-CSRF tokens, SameSite cookies, origin checks and re-authentication for sensitive actions.

We close the chapter with a different kind of trick, in which the user sees a real page but clicks on something else, and with the HTTP headers that give browsers the rules to prevent it.

Advertisement
Log in to save your progress. Log in