RestingOwl owl logo RestingOwl

CSRF (Cross-Site Request Forgery):Attacks & Defenses

Quick Answer: Cross-site request forgery (CSRF) tricks a logged-in user's browser into sending an unwanted request to a site they are authenticated on: for example, silently changing their email or transferring funds. It works because browsers attach cookies automatically to every request, even ones triggered by another site. The main defenses are anti-CSRF tokens, SameSite cookies, and verifying the Origin header for state-changing requests.

CSRF abuses the browser's own helpfulness: it sends your session cookie with every request to a site, no matter who triggered the request. That lets a malicious page act on your behalf without ever seeing your data. This guide explains how CSRF works, how it differs from XSS, and how to defend against it. It pairs with our guides on XSS and secure cookies.

What Is CSRF?

CSRF (also called XSRF or a 'confused deputy' attack) happens when an attacker causes a victim's browser to send a request to a site where the victim is already logged in. Because the browser automatically includes the victim's session cookie, the target site sees a fully authenticated request and processes it: even though the victim never intended to send it. The attacker cannot read the response; they can only trigger the action.

How Does a CSRF Attack Work?

Suppose a banking app changes the account email via a simple form POST. An attacker hosts a page that auto-submits that request. When a logged-in victim visits the malicious page, their browser sends the request with their session cookie attached:

<!-- On attacker.tld: auto-submits to the victim's bank -->
<form action="https://bank.example/email" method="POST">
  <input name="email" value="attacker@evil.tld">
</form>
<script>document.forms[0].submit()</script>

The bank receives an authenticated request to change the email and, with no CSRF defense, complies. The attacker now controls password resets for the account.

CSRF vs XSS: What Is the Difference?

DimensionCSRFXSS
What it abusesAutomatic cookie sending by the browserUntrusted data executed as script
Attacker can read response?No, only trigger the actionYes, full access to the page
Runs code in your origin?No, request comes from another siteYes, script runs in your origin
Primary defenseCSRF tokens + SameSite cookiesOutput encoding + CSP

An important relationship: XSS defeats CSRF protection. If an attacker has script execution via XSS, they can read the CSRF token and forge valid requests. That is why XSS is the higher priority to fix. See our XSS guide for that side of the story.

How Do You Prevent CSRF?

1. Anti-CSRF Tokens (Primary Defense)

Issue a unique, unpredictable token per session (or per request) and require it on every state-changing request. The token is delivered in the page (not as a readable cookie) and verified server-side. Because a cross-site attacker cannot read the token, they cannot forge a valid request. This is the synchronizer token pattern.

2. SameSite Cookies

Setting SameSite=Lax or SameSite=Strict on session cookies tells the browser not to send them on cross-site requests, which blocks most CSRF at the browser level. Lax is a sensible default; Strict is stronger but can break legitimate cross-site navigation. Treat SameSite as a strong baseline, not a complete replacement for tokens. We cover the cookie flags in detail in Session Management and Secure Cookies.

3. Verify Origin and Referer Headers

For state-changing requests, check that the Origin (or Referer) header matches your site. This is a useful defense-in-depth layer, since the browser sets these headers and a cross-site page cannot spoof its own origin.

4. Require Re-Authentication for Sensitive Actions

For high-value operations: changing a password, email, or making a payment: prompt for the password again or a second factor. Even if other defenses fail, the attacker cannot supply the credential.

CSRF Prevention Checklist

  • Use anti-CSRF tokens on all state-changing requests (POST, PUT, PATCH, DELETE)
  • Set SameSite=Lax or Strict on session cookies
  • Verify the Origin or Referer header for sensitive requests
  • Never use GET for actions that change state
  • Require re-authentication or MFA for high-value actions
  • Use your framework's built-in CSRF protection rather than rolling your own
  • Fix XSS first: it bypasses every CSRF control
Go deeper: CSRF, XSS, and session security are tightly linked. Read Cross-Site Scripting (XSS) and Session Management and Secure Cookies to complete the picture.

References

  1. 1OWASP Cross-Site Request Forgery Prevention Cheat Sheet
  2. 2OWASP CSRF
  3. 3MDN: SameSite cookies

Q&A Section

CSRF tricks a browser into sending an unwanted authenticated request, abusing the fact that cookies are sent automatically; the attacker cannot read the response, only trigger the action. XSS injects and executes malicious script inside your site's origin, giving the attacker full access to the page and its data. XSS is generally more powerful and can even bypass CSRF defenses by reading the CSRF token.
It prevents most CSRF, because the browser will not send the cookie on cross-site requests like a forged POST from another origin. However, browser support and edge cases vary, and some request flows are not fully covered, so OWASP recommends combining SameSite cookies with anti-CSRF tokens for state-changing actions rather than relying on SameSite alone.
It depends on how they authenticate. APIs that authenticate with cookies are vulnerable to CSRF and need protection. APIs that use a bearer token sent in an Authorization header (not automatically attached by the browser) are generally not vulnerable to classic CSRF, because the attacker's cross-site request cannot set that header.
It is the standard anti-CSRF technique: the server generates a unique, unpredictable token tied to the user's session, embeds it in forms or page state, and requires it back on every state-changing request. Because a cross-site attacker cannot read the token, they cannot forge a request that passes the server-side check.
Copied!