Conceptly
← All Concepts
🎭

Cross-Site Request Forgery

SecurityAn attack that abuses the browser's authenticated state to send requests the user never intended

CSRF (Cross-Site Request Forgery) is a web attack in which an attacker causes the victim's browser to send a request to a legitimate site by abusing the authentication state already stored in that browser. It is especially relevant when authentication is carried by cookies that the browser attaches automatically. From the server's perspective, a logged-in user is making the request, but that fact alone does not prove the request was actually intended by the user.

β–ΆArchitecture Diagram

πŸ”„ Process

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

The convenience of cookie-based authentication is that the browser automatically attaches the session cookie. The problem is that the same convenience can be exploited by an attacker. If a user is already logged in and then opens an attacker's page, that page can trigger requests to the legitimate site with hidden forms or other browser primitives. The browser does not decide whether the request reflects the user's intent; it simply sends the matching cookie along. From the server's point of view, it receives a valid authenticated request. It cannot tell whether the user deliberately clicked a button on the legitimate site or whether another site quietly caused the request to be sent. For state-changing actions, knowing who is logged in is not enough. The server also needs a way to verify that the request truly originated from the user's intention.

Why did this approach emerge?

Traditional server-rendered web applications relied heavily on form submissions and cookie-backed sessions. In that structure, visiting another site was enough to let the browser generate requests toward the original site, and cookies would be attached automatically. Early applications often assumed that simply distinguishing GET from POST was enough, but hidden auto-submitting forms and resource-loading tricks showed that dangerous actions could still be triggered. Frameworks later began to include CSRF tokens by default, and browsers strengthened defaults around SameSite cookies. Even so, CSRF remains an important boundary anywhere cookie-based authentication is used, especially in older form screens and redirect-based flows such as OAuth callbacks.

How does it work inside?

CSRF takes advantage of the fact that the user is already logged in. First, the user has an active session cookie for the legitimate site. Then the user visits an attack page. That page causes the browser to submit a hidden form or trigger another request toward the legitimate server. When the browser sees that the request targets the legitimate site, it automatically includes the session cookie. The critical point is on the server side. Because the request arrives with a valid session cookie, the server may mistake it for an intentional action from the user and carry out the state change if there is no additional verification. That is how password changes, email updates, and administrative operations can be triggered. The core defense is to include a signal in the request that the attack page cannot predict or replay. A CSRF token placed in a form or custom header and verified by the server does this. Origin and Referer checks add another layer. SameSite cookie settings reduce how often the browser will attach cookies on cross-site requests, but they do not solve every case on their own.

In Code

Including a CSRF token in the form

<form method="post" action="/api/profile/email">
  <input type="hidden" name="csrfToken" value="{{csrfToken}}" />
  <button type="submit">Save</button>
</form>

Read this as the client-side half of request verification. The server must compare the hidden value against the session, not trust the cookie alone.

Proving intent with a request header

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

SPAs usually send the token in a custom header instead of a form field. The browser may attach cookies automatically, but the server still has to verify this header explicitly.

What is it often confused with?

CSRF and XSS both route through the browser, but the decisive difference is code execution. XSS runs JavaScript inside a trusted page, so it can read responses, modify the UI, and steal tokens. CSRF usually only causes a request to be sent from another site and often cannot read the response. A second frequent confusion is the relationship with CORS. CORS controls whether JavaScript may read a cross-origin response, but it does not stop the browser from sending the request in the first place. That is why strict CORS settings do not automatically eliminate CSRF. Request authenticity is a separate problem.

When should you use it?

In practice, the first review target is any endpoint that changes state. Profile updates, password changes, purchase requests, and destructive admin actions are the highest priorities because the damage is immediate if they are triggered unintentionally. In server-rendered forms, the common pattern is to embed a hidden CSRF token. In SPAs, the server typically issues a token that the client sends back in a custom header. Cookie policy matters as well. SameSite=Lax or Strict reduces when cookies are attached to cross-site requests and raises the default defensive baseline. But redirect-based flows such as OAuth still need their own protection, which is why the state parameter matters. Finally, 'it's a POST request, so it's safe' is a dangerous assumption. Changing the HTTP method does not prove the request was intentional. The lowest-maintenance approach is to design state-changing endpoints with token verification and origin checks from the beginning.

Account setting changes -- forged requests for email, password, or address updatesFinance and checkout flows -- transfers or purchases triggered solely because the user is already logged inAdmin panels -- external links that trigger privilege changes or destructive actionsOAuth redirect handling -- missing state validation that lets the app accept an unsolicited authorization response