SecurityMedium

How does CSRF work?

01

The Short Answer

Cross-Site Request Forgery (CSRF) is an attack that tricks a user's browser into making an unwanted request to a site where they're already authenticated. The attacker exploits the fact that browsers automatically attach cookies (including session cookies) to every request to a domain, regardless of where the request originated.

02

How the Attack Works

CSRF exploits the trust a website has in the user's browser. If you're logged into your bank and visit a malicious page, that page can trigger requests to your bank — and your browser will helpfully attach your session cookie.

Here's the step-by-step attack flow:

  • User logs into bank.com — the browser stores a session cookie
  • User visits malicious-site.com in another tab (maybe via a phishing link)
  • The malicious page contains a hidden form or image tag that targets bank.com
  • The browser sends the request to bank.com and automatically attaches the session cookie
  • Bank.com sees a valid session cookie and processes the request as legitimate
  • Money is transferred, email is changed, or whatever action the attacker targeted — all without the user's knowledge

Why it works

The browser doesn't care where the request originates — it attaches cookies for the target domain regardless. The server receives a perfectly valid session cookie and has no way to tell the difference between a legitimate request and a forged one.

03

Attack Examples

CSRF attacks can be surprisingly simple. In the example below, a malicious page contains a hidden form with pre-filled values targeting your bank. The moment the page loads, JavaScript auto-submits the form — and because your browser still has a valid session cookie for bank.com, the bank processes it as if you made the request yourself.

csrf-hidden-form.htmlhtml
<!-- On malicious-site.com -->
<!-- Hidden form that auto-submits -->
<form action="https://bank.com/transfer" method="POST" id="evil-form">
  <input type="hidden" name="to" value="attacker-account" />
  <input type="hidden" name="amount" value="10000" />
</form>
<script>
  document.getElementById('evil-form').submit();
</script>

Attackers don't even need forms — they can use image tags and hidden iframes to trigger requests silently. An <img> tag with a bank URL as its src fires a GET request the moment the page loads, and a hidden iframe can receive a form submission without the user ever seeing a page navigation. None of these require any clicks or interaction from the victim.

csrf-image-tag.htmlhtml
<!-- Even simpleran image tag triggers a GET request -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" width="0" height="0" />

<!-- Hidden iframe with form -->
<iframe style="display:none" name="csrf-frame"></iframe>
<form action="https://bank.com/change-email" method="POST" target="csrf-frame">
  <input type="hidden" name="email" value="attacker@evil.com" />
</form>
<script>document.forms[0].submit();</script>
04

What the Attacker Cannot Do

Understanding CSRF's limitations helps you understand why certain defenses work:

  • The attacker cannot read the response — they can trigger actions but can't see what comes back (same-origin policy blocks this)
  • The attacker cannot read or set cookies for another domain — they can only cause the browser to send existing cookies
  • The attacker cannot set custom headers on cross-origin requests — this is why custom headers are a defense
  • The attacker cannot forge requests that require data only available on the target page (like a CSRF token)
05

Prevention Methods

There are several proven defenses against CSRF. Modern applications typically use multiple layers (defense in depth).

1. CSRF Tokens (Synchronizer Token Pattern)

The server generates a unique, unpredictable token for each session or form. This token is embedded in the page as a hidden field. On submission, the server verifies the token matches. Since the attacker can't read the target page, they can't know the token.

csrf-token.tstypescript
// Server: Generate token and embed in page
import crypto from 'crypto';

function generateCsrfToken(session: Session): string {
  const token = crypto.randomBytes(32).toString('hex');
  session.csrfToken = token;
  return token;
}

// HTML form includes the token as a hidden field:
// <input type="hidden" name="_csrf" value="a8f2e9..." />

// Server middleware: Validate on state-changing requests
function csrfProtection(req: Request, session: Session): boolean {
  if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) return true;
  const token = req.body._csrf || req.headers['x-csrf-token'];
  return token === session.csrfToken;
}

2. SameSite Cookie Attribute

The SameSite cookie attribute tells the browser when to include cookies in cross-site requests. When set to lax or strict, the browser simply won't attach the cookie to requests that originate from a different site — which kills the entire CSRF attack vector at the browser level. Pay attention to the three possible values and what each one blocks.

samesite-cookies.tstypescript
res.cookie('session_id', sessionId, {
  httpOnly: true,      // Not accessible via JavaScript
  secure: true,        // Only sent over HTTPS
  sameSite: 'lax',    // The key CSRF defense
  maxAge: 3600000,
});

// SameSite values:
// 'strict' — Cookie NEVER sent on cross-site requests
// 'lax'    — Cookie sent on top-level navigations (links)
//            but NOT on cross-site POST, iframes, or AJAX
// 'none'   — Cookie always sent (old behavior, requires Secure)

Since 2020, Chrome defaults to SameSite=Lax for cookies that don't specify a value. This single change eliminated most CSRF attacks on the modern web.

3. Custom Request Headers

Cross-origin requests from forms and image tags cannot set custom headers. Only JavaScript using fetch() or XMLHttpRequest can — and the same-origin policy blocks cross-origin JavaScript from reading responses. So requiring a custom header proves the request came from your own site.

4. Verify Origin/Referer Headers

Check that the Origin or Referer header matches your domain. Requests from malicious sites will have a different origin. This is a defense-in-depth measure — not sufficient alone since headers can sometimes be stripped.

06

CSRF vs XSS

These two attacks are often confused but work in opposite directions:

AspectCSRFXSS
ExploitsTrust the server has in the user's browserTrust the user has in the website
Attacker's goalPerform actions as the victimSteal data or execute code in victim's browser
Can read response?No — just triggers the action blindlyYes — can read cookies, DOM, everything
PreventionCSRF tokens, SameSite cookiesInput sanitization, CSP, HttpOnly cookies

Important relationship

If your site has an XSS vulnerability, CSRF protections become useless. An XSS attack can read CSRF tokens from the page and bypass all CSRF defenses. Always fix XSS first.

07

Why Interviewers Ask This

CSRF is one of the OWASP Top 10 web vulnerabilities. Interviewers ask this to verify you understand how browser cookie behavior can be exploited, and that you know practical prevention strategies. Being able to explain the attack flow step-by-step, name multiple defenses, and compare CSRF with XSS shows solid security awareness.

Quick Revision Cheat Sheet

What is CSRF: Tricking a browser into making authenticated requests to a site the user is logged into

Root cause: Browsers auto-attach cookies to requests regardless of where the request originated

Best defense: CSRF tokens + SameSite=Lax cookies + custom headers (defense in depth)

Safe methods: GET, HEAD, OPTIONS don't need CSRF protection (they should never mutate state)

Modern default: Chrome defaults to SameSite=Lax since 2020, blocking most CSRF attacks automatically