How to Prevent CSRF Attacks in Modern Web Apps

Cross-Site Request Forgery (CSRF) occurs when a malicious website tricks an authenticated user’s browser into executing unwanted actions on a trusted application. Preventing CSRF in modern web development requires a defense-in-depth approach combining browser-level features, cryptographic validation, and framework safeguards. This article outlines the primary measures developers use to prevent CSRF attacks, including modern cookie attributes, anti-CSRF tokens, header validation, and interaction-based challenges.

The SameSite attribute tells the browser whether to send cookies along with cross-site requests. This is the first and often most effective line of defense for session cookies.

  • SameSite=Strict: The browser never sends the cookie in cross-site contexts, not even when a user clicks an external link to the site. This offers the highest security.
  • SameSite=Lax: The browser permits cookies on safe, top-level navigations (such as clicking a normal link via a GET request), but blocks cookies for cross-origin state-changing methods like POST, PUT, or DELETE. Most modern browsers default to Lax if no attribute is specified.
  • SameSite=None; Secure: Allows third-party usage, but requires the Secure flag so cookies are only transmitted over HTTPS. Avoid this setting for authentication cookies whenever possible.

2. Use Anti-CSRF Tokens (Synchronizer Token Pattern)

Anti-CSRF tokens remain a standard mitigation for server-rendered applications and forms.

  • The server generates a cryptographically strong, unpredictable, and unique token tied to the user's current session.
  • When rendering a form, this token is embedded as a hidden input field.
  • Upon submission, the server compares the incoming token against the stored session value. If the values do not match or the token is missing, the request is rejected.
  • Because malicious sites cannot read response data across origins due to the Same-Origin Policy (SOP), an attacker cannot obtain this token to forge a valid payload.

For stateless architectures, APIs, or Single Page Applications (SPAs) where server-side session tracking is undesirable, the Double Submit Cookie pattern provides an alternative:

  • The server sets a cryptographically random value in a cookie accessible by JavaScript.
  • When sending a state-changing request, the client-side code reads this value and inserts it into a custom HTTP request header (e.g., X-XSRF-TOKEN).
  • The server validates that the cookie value matches the header value. Since cross-origin scripts cannot read the cookie from another domain, an attacker cannot forge the matching header.

4. Verify Origin and Referer Headers

Modern browsers automatically include the Origin and Referer HTTP headers in cross-origin requests. Servers can inspect these headers to detect unauthorized sources:

  1. Check the Origin header first; modern browsers send it with POST, PUT, PATCH, and DELETE requests.
  2. Fall back to the Referer header if Origin is absent.
  3. Ensure the header domain matches the application's target origin. If neither header is present or if the domain does not match, reject the request.

5. Use Custom Request Headers for APIs

APIs that rely on standard JavaScript clients (fetch or Axios) can mandate custom headers, such as X-Requested-With: XMLHttpRequest or custom authorization tokens (e.g., Authorization: Bearer <token>).

Standard HTML elements (such as <form>, <img>, or <iframe>) cannot send custom HTTP headers cross-origin without triggering a Cross-Origin Resource Sharing (CORS) preflight check (OPTIONS request). By requiring custom headers and configuring strict CORS policies, the API ensures only explicitly allowed origins can send the request.

6. Enforce Re-Authentication for Sensitive Actions

For critical operations—such as updating passwords, changing recovery emails, or transferring funds—require the user to re-enter their current password, supply a Multi-Factor Authentication (MFA) code, or solve a CAPTCHA. This prevents automated, blind CSRF attacks from completing unauthorized high-impact tasks even if other layers fail.