DEV_NET_CORE
GET_STARTED
Design & ArchitectureWeb application security threat modeling and attack patterns

Cross-Site Request Forgery and how cookie-based authentication changes the risk model

Overview

Cross-Site Request Forgery (CSRF) is an attack in which a malicious site causes a victim's browser to send an unwanted request to another application where the victim is authenticated.

The attacker does not need to read the response. The attack succeeds when the browser automatically attaches credentials, the server accepts the request, and the request changes state without independent proof that the legitimate application initiated it.

Cookie-based authentication changes the risk model because cookies are ambient credentials. The browser decides whether to attach them from cookie attributes such as domain, path, Secure, and SameSite; it does not use the trustworthiness of the page that initiated the request. A cross-site form, image, navigation, or script may therefore trigger an authenticated request.

By contrast, a bearer token that client code explicitly places in an Authorization header is not normally attached to a cross-site request automatically. This reduces classical CSRF exposure, although it introduces other concerns such as XSS, token storage, CORS configuration, and token leakage. A backend-for-frontend (BFF) that stores tokens server-side but authenticates the browser with a cookie remains subject to CSRF.

CSRF matters in interviews because it tests whether a candidate can reason about browser behavior, authentication transport, HTTP method semantics, cross-origin restrictions, and layered defenses. Strong answers explain why the same-origin policy and CORS do not by themselves stop forged requests, and why SameSite cookies are useful but should not be the only control for sensitive operations.

Core Concepts

Attack Preconditions

A typical CSRF attack requires:

  • A victim who is authenticated to the target application.
  • Credentials that the browser attaches automatically, usually a session cookie.
  • A predictable state-changing endpoint and request shape.
  • A request the attacker can cause a browser to send.
  • No effective anti-forgery, origin, or same-site validation.

For example, a vulnerable transfer endpoint might accept:

Code
POST /api/transfers HTTP/1.1
Content-Type: application/x-www-form-urlencoded

to=attacker&amount=1000

An attacker-controlled page could submit the same request:

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

If the browser includes the victim's session cookie and the server requires no additional proof of intent, the server may process the transfer.

Same-Origin Policy Does Not Stop Requests

The same-origin policy generally prevents a malicious origin from reading another origin's protected response. It does not prevent every cross-origin request from being sent.

Browsers intentionally support cross-origin:

  • HTML form submissions.
  • Top-level navigations.
  • Images, stylesheets, and other embedded resources.
  • Some script-issued "simple" requests.

CSRF often needs only a side effect. The attacker may not care whether the response is readable.

Consider a session cookie:

Code
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

HttpOnly prevents JavaScript from reading the cookie, which helps limit cookie theft through some XSS attacks. It does not stop the browser from attaching the cookie to eligible requests and therefore is not a CSRF defense.

The key distinction is:

Authentication transportBrowser behaviorClassical CSRF risk
Session cookieAutomatically attached when cookie rules permitPresent
JWT in a cookieAutomatically attached like any other cookiePresent
Bearer token in AuthorizationClient code normally adds it explicitlyUsually reduced
Mutual TLS client certificateBrowser or client may present it automaticallyCan be present
BFF session cookieAutomatically attached to the BFFPresent

The token format does not determine CSRF risk. A JWT stored in a cookie is still an ambient credential.

Unsafe HTTP Methods

GET, HEAD, OPTIONS, and TRACE are defined as safe methods: they should not change application state.

This endpoint is dangerous:

Code
GET /account/delete?id=42

An attacker may trigger it with:

Code
<img src="https://app.example/account/delete?id=42" alt="">

State changes should use methods such as POST, PUT, PATCH, or DELETE, and those methods should be protected. Using POST is necessary but not sufficient because cross-site forms can submit POST requests.

Synchronizer Token Pattern

The synchronizer token pattern generates an unpredictable token associated with the user's authenticated session.

The legitimate application includes the token in:

  • A hidden form field.
  • A custom request header.
  • Another request location not automatically populated by the browser.

The server verifies that the submitted token matches the session before processing the request.

Code
<form method="post" action="/profile/email">
  <input type="hidden" name="__RequestVerificationToken"
         value="unpredictable-session-bound-token">
  <input type="email" name="email">
  <button type="submit">Change email</button>
</form>

A malicious site can cause the browser to send the session cookie, but it should not be able to read the legitimate page and obtain the token.

Good anti-forgery tokens are:

  • Generated with a cryptographically secure source.
  • Unpredictable.
  • Bound to the intended session or authentication context.
  • Compared using the framework's supported validation mechanism.
  • Excluded from URLs and logs.

In a double-submit design, the server sends a CSRF token in a cookie and the client echoes the value in a form field or custom header. The server compares both values.

Code
Cookie: csrf=RANDOM_VALUE
X-CSRF-TOKEN: RANDOM_VALUE

A robust implementation should sign the token and bind it to session-specific data. A naive comparison of two attacker-injectable values can fail if an attacker can plant or overwrite cookies through a vulnerable subdomain or other cookie-injection path.

Use a framework implementation when available rather than designing a custom token format.

Custom Headers and Preflight

HTML forms cannot set arbitrary custom headers. Requiring a header such as X-CSRF-TOKEN can therefore distinguish requests made by approved application code from ordinary cross-site form submissions.

Code
await fetch("/api/profile/email", {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
    "X-CSRF-TOKEN": csrfToken,
  },
  body: JSON.stringify({ email }),
});

Cross-origin JavaScript that sends a custom header normally triggers a CORS preflight. The server must allow only exact trusted origins when credentials are enabled.

Do not treat CORS as authorization:

  • CORS controls whether browser JavaScript may make or read certain cross-origin requests.
  • It does not protect non-browser clients.
  • A permissive or reflected origin policy can undermine a custom-header CSRF design.
  • Compromised trusted origins remain dangerous.

SameSite Cookies

SameSite controls whether cookies are sent in cross-site contexts.

  • Strict provides the strongest cross-site restriction but can disrupt legitimate incoming links and federated flows.
  • Lax permits cookies in some top-level navigation scenarios while blocking many cross-site subrequests.
  • None permits cross-site use and requires Secure.

Important limitations:

  • "Site" is not the same as "origin." Different subdomains can be same-site while being cross-origin.
  • Some authentication, payment, embedded, and federation flows require deliberate exceptions.
  • Legacy clients and unusual browser behavior may differ.
  • A state-changing GET remains unsafe.
  • A vulnerable or attacker-controlled sibling subdomain can affect the trust model.

Set SameSite deliberately, but retain token validation or equivalent proof of request intent for sensitive cookie-authenticated operations.

Origin and Referer Validation

For state-changing requests, a server can verify that the Origin header matches an exact trusted origin. If Origin is unavailable, a carefully parsed Referer header may be a fallback.

Validation should:

  • Compare parsed scheme, host, and port.
  • Use an explicit allowlist.
  • Reject suffix tricks such as trusted.example.attacker.test.
  • Account for reverse proxies and the application's canonical external origin.
  • Define a cautious policy for missing or null origins.

Header validation is useful defense in depth and can be a primary control in some architectures, but teams must understand compatibility requirements before rejecting all missing headers.

Fetch Metadata

Modern browsers may send Fetch Metadata headers such as:

Code
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document

A server can reject clearly cross-site requests to sensitive endpoints while allowing same-origin or same-site traffic according to policy.

Fetch Metadata is defense in depth:

  • Not every client sends the headers.
  • Same-site subdomains may still be untrusted.
  • Webhooks, APIs, and legacy integrations may require separate policies.
  • It should complement, not silently replace, established anti-forgery protection.

ASP.NET Core Antiforgery

ASP.NET Core provides antiforgery services for cookie-authenticated applications. MVC and Razor Pages can generate and validate tokens through built-in helpers, filters, and attributes.

Code
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "X-CSRF-TOKEN";
});

A controller can require validation:

Code
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ChangeEmail(ChangeEmailRequest request)
{
    // Perform the authorized state change.
    return NoContent();
}

For a JavaScript client, the application can issue a request token through an authenticated same-origin endpoint and require the client to return it in the configured header. The framework maintains the corresponding cookie token and validates the pair.

Key implementation rules:

  • Register antiforgery services and ensure validation actually runs.
  • Protect all cookie-authenticated unsafe methods, not only selected forms.
  • Do not expose tokens in query strings.
  • Do not disable validation broadly to fix one integration.
  • Separate browser endpoints from webhook or machine-to-machine endpoints when their trust models differ.

SPA and BFF Architectures

A single-page application may use one of two broad models.

Token-based browser API client

  • The client adds an access token to Authorization.
  • The browser does not automatically attach that header to an attacker's form.
  • Classical CSRF is reduced.
  • XSS and token-storage decisions become especially important.

Cookie-authenticated SPA or BFF

  • The browser automatically sends the session cookie.
  • The application needs CSRF protection for state-changing endpoints.
  • The SPA commonly obtains a CSRF token and returns it in a custom header.
  • credentials: "include" and CORS policies must be tightly controlled when origins differ.

Moving tokens into a BFF can reduce token exposure to browser JavaScript, but the cookie-facing boundary must still handle CSRF.

JSON Does Not Automatically Prevent CSRF

Requiring application/json and rejecting form content types blocks ordinary HTML forms from reproducing a JSON request. This can be a useful layer when combined with a required custom header and restrictive CORS.

It is not a universal substitute for anti-forgery validation:

  • Endpoints may accidentally accept form or text content.
  • Parsers and middleware may support unexpected formats.
  • CORS may be overly permissive.
  • Browser behavior and integrations evolve.

Explicitly constrain accepted methods and content types, then enforce the intended CSRF control.

Login CSRF

CSRF is not limited to operations performed after a victim logs in. In login CSRF, an attacker causes the victim's browser to authenticate to the application using the attacker's account.

The victim may then enter:

  • Personal information.
  • Payment details.
  • Search history.
  • Uploaded data.

The attacker later signs in to the same account and sees that information. Login endpoints and account-linking flows therefore need request correlation and anti-forgery protection.

CSRF and XSS

CSRF and XSS are different:

  • CSRF causes a browser to send an authenticated request without proving user intent.
  • XSS executes attacker-controlled script in the trusted origin.

An XSS vulnerability can often read CSRF tokens and send valid same-origin requests, bypassing CSRF defenses. This does not make CSRF protection unnecessary; it means both vulnerability classes must be addressed.

Sensitive Operations and Reauthentication

High-impact operations should use layered controls:

  • Anti-forgery validation.
  • Authorization against the requested action and resource.
  • Recent reauthentication or step-up MFA.
  • Transaction confirmation that displays critical values.
  • Rate limits and anomaly detection.
  • Audit logs and user notifications.

A CSRF token proves that a request likely came through an approved application context. It does not prove that the user is authorized, recently authenticated, or knowingly approved every transaction detail.

Common Mistakes

Common implementation failures include:

  • Assuming POST prevents CSRF.
  • Using HttpOnly as a CSRF control.
  • Storing a JWT in a cookie and assuming JWTs are immune.
  • Protecting HTML forms but not JSON, upload, GraphQL, or batch endpoints.
  • Accepting state changes through GET.
  • Using predictable or globally shared tokens.
  • Logging tokens or placing them in URLs.
  • Allowing arbitrary credentialed CORS origins.
  • Trusting all same-site subdomains.
  • Disabling antiforgery validation for an entire controller.
  • Comparing Origin with substring or suffix checks.
  • Relying on SameSite alone for critical operations.

Best-Practice Decision Process

For each browser-facing endpoint:

  1. Identify whether the browser attaches authentication automatically.
  2. Classify the method as safe or state-changing.
  3. Determine which origins and sites legitimately initiate the request.
  4. Apply framework-supported anti-forgery validation to cookie-authenticated unsafe methods.
  5. Set restrictive cookie attributes: Secure, HttpOnly, appropriate domain and path, and deliberate SameSite.
  6. Validate exact origins and consider Fetch Metadata as additional controls.
  7. Restrict content types and credentialed CORS policies.
  8. Add authorization, reauthentication, and transaction confirmation according to impact.
  9. Test negative cases from an attacker-controlled origin.

Interview Practice

PreviousCommand injection, file upload risks, path traversal, secrets exposure, and DoS/DDoS basicsNext UpCross-Site Scripting, output encoding, dangerous HTML rendering, and content security controls