Skip to content

What is a CSRF token and how does it prevent forgery attacks?

Sep 15, 2026 · Security

A CSRF token is an unpredictable, secret value that a server generates for a user’s session and requires to be echoed back on every state-changing request, so it can confirm the request originated from its own trusted pages rather than from an attacker’s site. Cross-site request forgery (CSRF) tricks a logged-in user’s browser into silently submitting a request the user never intended. Because browsers attach cookies automatically to any request aimed at a domain, a malicious page can forge authenticated actions. The token breaks this because a third-party site cannot read or guess it.

Key takeaways

  • A CSRF token proves a request came from your own UI, not a forged cross-site request that rides on the user’s cookies.
  • Only state-changing methods (POST, PUT, PATCH, DELETE) need protection; safe methods like GET must not mutate state.
  • The token must be unpredictable, tied to the user’s session, and validated server-side on every mutating request.
  • Two common patterns are the synchronizer token (stored server-side) and the double-submit cookie (stateless).
  • Set SameSite on session cookies as a second layer, but do not rely on it alone.
  • CSRF tokens do not defend against XSS; an injected script can read the token and defeat the protection entirely.

How does a CSRF attack actually work?

CSRF exploits a simple browser behavior: cookies for a domain are sent on every request to that domain, regardless of which site initiated the request. If a user is authenticated to bank.example and visits a hostile page, that page can trigger a request to the bank, and the browser dutifully attaches the session cookie.

Consider a hostile page containing an auto-submitting form:

<form action="https://bank.example/transfer" method="POST">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="1000">
</form>
<script>document.forms[0].submit()</script>

The victim never clicked anything meaningful, yet the bank receives a fully authenticated transfer request. The server cannot distinguish it from a legitimate one using cookies alone. A CSRF token fixes this: the real transfer form includes a secret the attacker’s page cannot obtain, so the forged request lacks it and is rejected.

What makes a CSRF token secure?

The token’s entire value comes from being unguessable and bound to the current user. Three properties matter:

  • Unpredictability: generate it from a cryptographically secure random source, not a timestamp, counter, or weak hash.
  • Session binding: the token must be associated with the authenticated user so a token from one session cannot be replayed in another.
  • Confidentiality across origins: the same-origin policy prevents a cross-site page from reading the token out of your DOM or a non-readable response, which is what keeps the attacker blind.

Length should provide ample entropy; a value on the order of 128 bits or more of randomness, encoded as hex or base64, is standard practice. Never derive it from data the attacker can compute.

What is the difference between synchronizer tokens and double-submit cookies?

There are two dominant server-side strategies. The synchronizer token pattern stores the token in server-side session state and compares the submitted value against it. The double-submit cookie pattern is stateless: the server sets the token in a cookie and also requires it in a request header or body, then checks that the two match.

Aspect Synchronizer token Double-submit cookie
Server state Requires session storage Stateless
Validation Compare submitted value to stored value Compare cookie value to header or body value
Scaling Needs shared session store across nodes Easy to scale horizontally
Main risk Session store overhead Subdomain cookie injection if not hardened

The double-submit approach works because a cross-site attacker can force the browser to send the cookie but cannot read it to place a matching copy in a custom header. For extra strength, sign the cookie value or bind it to the session so an attacker on a sibling subdomain cannot inject an arbitrary token.

How do I add a CSRF token to a form and to AJAX?

For traditional server-rendered forms, embed the token as a hidden field:

<form method="POST" action="/account/email">
  <input type="hidden" name="csrf_token" value="9f2c...a71">
  <input type="email" name="email">
  <button>Save</button>
</form>

For single-page apps and fetch calls, expose the token via a meta tag and send it in a custom request header. Custom headers are ideal because browsers will not let a cross-origin page set arbitrary headers without a passing CORS preflight:

const token = document
  .querySelector('meta[name="csrf-token"]')
  .getAttribute('content');

fetch('/account/email', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': token
  },
  body: JSON.stringify({ email: 'new@example.com' })
});

On the server, read the header, compare it to the expected value with a constant-time comparison, and reject the request with 403 when it is missing or wrong.

Which requests actually need CSRF protection?

Protect anything that changes state. Follow HTTP semantics: GET, HEAD, and OPTIONS are defined as safe and must never mutate data, so they do not require a token. Requiring a token on GET is both unnecessary and a smell that the endpoint is doing something it should not.

  • Needs a token: POST, PUT, PATCH, DELETE that modify server state.
  • Does not need a token: read-only GET endpoints and idempotent lookups.

If you find yourself mutating data on a GET, fix the endpoint rather than bolting a token onto it, because forged image or link requests can trigger GET silently.

How do SameSite cookies and CSRF tokens work together?

The SameSite cookie attribute tells the browser whether to send a cookie on cross-site requests. SameSite=Lax withholds the cookie on most cross-site subrequests while still allowing top-level navigations, and SameSite=Strict withholds it even then. Many browsers now default to Lax, which blocks the classic hidden-form POST attack outright.

However, treat SameSite as defense in depth, not a replacement. Some flows legitimately need cross-site cookies, older clients may not enforce the attribute, and misconfigurations happen. Layering a token on top ensures protection even when cookie behavior varies. Set your session cookie with HttpOnly, Secure, and an appropriate SameSite value, and keep the token check in place.

What are the most common CSRF implementation mistakes?

Several recurring errors quietly disable the protection:

  • Validating only when a token is present: if a missing token is treated as valid, attackers simply omit it. Reject requests that lack the token.
  • Comparing tokens with a non-constant-time equality check: use a constant-time comparison to avoid timing side channels.
  • Leaking the token in a URL: tokens in query strings end up in logs, browser history, and Referer headers. Keep them in bodies or headers.
  • Assuming CSRF tokens stop XSS: if an attacker can run script on your origin, they can read the token. Fix XSS separately with output encoding and a content security policy.
  • Sharing one global token across users: the token must be per-session so it cannot be harvested and reused.
  • Forgetting AJAX and API routes: cookie-authenticated JSON endpoints are just as vulnerable as form posts.

A framework’s built-in CSRF middleware handles most of this correctly; prefer it over a handwritten scheme, and make sure it is enabled on every mutating route rather than a subset. When you must customize it, change configuration rather than reimplementing the token generation and comparison, since those are exactly the parts that are easy to get subtly wrong.

Finally, treat CSRF protection as one layer in a defense-in-depth strategy. Combine the token with a properly scoped session cookie carrying HttpOnly, Secure, and SameSite, enforce authentication and authorization on every sensitive action, and eliminate cross-site scripting so an attacker cannot read the token in the first place. No single control is sufficient alone, but together they make cross-site request forgery impractical.

Frequently asked questions

What is a CSRF token in simple terms?

It is an unpredictable secret value the server issues and expects back on state-changing requests, proving the request came from your own page rather than a malicious cross-site one.

Where should a CSRF token be stored?

Typically in server-side session state, or a signed cookie for the double-submit pattern, and rendered into forms as a hidden field or exposed to JavaScript via a meta tag or readable cookie.

Do CSRF tokens protect GET requests?

They should not be needed for GET, because GET must be safe and non-mutating. Protect only state-changing methods like POST, PUT, PATCH, and DELETE.

Does SameSite cookie protection replace CSRF tokens?

SameSite Lax or Strict blocks many cross-site requests and is a strong layer, but tokens remain the most robust defense, so use both together.

Are CSRF tokens needed for token-based APIs?

If a request is authenticated by an Authorization header the browser never adds automatically, CSRF risk largely disappears. Cookie-authenticated APIs still need protection.

What is the difference between CSRF and XSS?

CSRF abuses a user’s existing authenticated session from another site, while XSS injects and runs attacker script in your page. CSRF tokens do not stop XSS.

Should each request use a new CSRF token?

Per-session tokens are common and sufficient for most apps. Per-request rotation adds defense in depth but complicates concurrent tabs and AJAX.

Frequently asked questions

What is a CSRF token in simple terms?

It is an unpredictable secret value the server issues and expects back on state-changing requests, proving the request came from your own page rather than a malicious cross-site one.

Where should a CSRF token be stored?

Typically in server-side session state (or a signed cookie for the double-submit pattern) and rendered into forms as a hidden field or exposed to JavaScript via a meta tag or readable cookie.

Do CSRF tokens protect GET requests?

They should not be needed for GET, because GET must be safe and non-mutating. Protect only state-changing methods like POST, PUT, PATCH, and DELETE.

Does SameSite cookie protection replace CSRF tokens?

SameSite=Lax or Strict blocks many cross-site requests and is a strong layer, but tokens remain the most robust defense, so use both together.

Are CSRF tokens needed for token-based APIs?

If a request is authenticated by an Authorization header the browser never adds automatically, CSRF risk largely disappears. Cookie-authenticated APIs still need protection.

What is the difference between CSRF and XSS?

CSRF abuses a user's existing authenticated session from another site, while XSS injects and runs attacker script in your page. CSRF tokens do not stop XSS.

Should each request use a new CSRF token?

Per-session tokens are common and sufficient for most apps. Per-request rotation adds defense in depth but complicates concurrent tabs and AJAX.

Contact: contact@quikconsolecom.net