1

Remediation

CSRF Tokens

🛡️

Remediation

As a defense, the token approach remains one of the most broadly applicable controls on this list. Unlike SameSite, it does not depend primarily on browser cookie policy to prevent the attack. Instead, it requires the request to contain an additional unpredictable value that an attacker-controlled origin cannot normally read or obtain. The browser may still send the victim's session cookie with a forged request, but without the corresponding valid CSRF token, the server rejects the request.

Its main cost is implementation complexity: tokens must be generated securely, associated with the appropriate session or request, validated correctly, and enforced consistently across every state-changing endpoint.

The central principle is: SameSite limits when the browser sends the victim's credentials; a CSRF token gives the server an independent value with which to verify that a state-changing request is legitimate. The token is effective only when its validation is correct and consistently enforced.

2

Remediation

SameSite Cookies

🛡️

Remediation

SameSite=Strict or SameSite=Lax on the session cookie is the browser-enforced counterpart to the application-level token — it restricts when the browser attaches the cookie to cross-site requests, reducing the ambient-authority mechanism, rather than requiring the server to detect every forged request after it arrives.

Set-Cookie: session=abc123def456; SameSite=Strict; Secure; HttpOnly

SameSite=Strict : the cookie is withheld from cross-site contexts, including top-level navigations. This provides the strongest cross-site restriction, but can introduce usability friction: when a user follows an external link to the application, the session cookie may not be sent with that initial navigation, so the user can appear logged out until they navigate within the site again. The underlying server-side session has not necessarily been destroyed.

SameSite=Lax : the cookie is still withheld from most cross-site subresource and script-driven requests, but can be sent on eligible top-level navigations using safe methods such as GET. This is a common practical default, but it leaves incorrectly designed GET-based state-changing endpoints potentially exploitable and still has the edge cases and bypass scenarios.

It also does not protect authentication mechanisms that do not rely on cookies. And it does not necessarily protect against CSRF-like requests that originate from a context the browser considers same-site rather than cross-site. This is relevant to the stored-CSRF variation, where attacker-controlled content hosted within the trusted site's site boundary may be able to trigger the request without crossing the SameSite boundary.

The two defenses therefore operate at different layers:

Cross-site forged request
          │
          ▼
   SameSite cookie policy
          │
          ├── Cookie withheld
          │       ↓
          │   Request unauthenticated
          │
          └── Cookie sent
                  │
                  ▼
          Server-side CSRF check
                  │
                  ├── Valid token → allowed
                  │
                  └── Missing/invalid token → rejected

The central principle is: SameSite reduces CSRF risk by controlling when the browser automatically sends cookie-based credentials; CSRF tokens provide an independent server-side check that the state-changing request contains a value the attacker cannot normally obtain. They complement each other rather than serving as interchangeable defenses.

3

Remediation

Origin Validation

🛡️

Remediation

Modern browsers commonly send an Origin header on state-changing requests such as POST, PUT, PATCH, and DELETE. The header identifies the origin that initiated the request:

POST /api/account/password HTTP/1.1
Origin: https://evil.com

The server can compare this value against an explicit allow-list of legitimate origins and reject requests from anything else:

Origin: https://evil.com
          │
          ▼
   Compare with allow-list
          │
          ├── https://app.example.com → allowed
          │
          └── https://evil.com       → rejected

For a normal browser-based CSRF attack, JavaScript running on evil.com cannot simply change the browser-generated Origin header to https://app.example.com. This makes the header useful as an independent signal of where the request originated.

Origin validation is therefore a strong and relatively simple server-side defense, particularly for APIs and other state-changing endpoints where the expected origins are well defined.

However, it has an important limitation: the absence of an Origin header is not equivalent to a trusted origin. Depending on the request type, browser behavior, navigation context, privacy mechanisms, or client implementation, a request may legitimately arrive without an Origin header. Non-browser HTTP clients can also construct requests without one or supply their own header.

The server therefore needs an explicit policy for missing or unexpected values:

                Request
                   │
                   ▼
             Origin present?
              /          \
            yes           no
             │             │
             ▼             ▼
      Is it allowed?   Apply explicit
         /     \       missing-Origin policy
       yes      no
        │        │
        ▼        ▼
      allow    reject

The central principle is: Origin validation asks the server where the request says it originated, while a CSRF token asks for a value that an untrusted origin should not possess. Origin checking is a useful independent layer, but missing headers and non-browser clients mean it should be implemented with an explicit policy rather than treating absence as proof of safety.

4

Remediation

Referer Validation

🛡️

Remediation

The Referer header — the misspelling is part of the original HTTP specification — can serve a similar purpose to Origin: the server can inspect where the request came from and compare it against an expected site or origin.

POST /api/account/password HTTP/1.1
Referer: https://app.example.com/account/settings

A server might therefore accept requests whose Referer belongs to its own trusted origin and reject requests originating elsewhere:

Referer: https://evil.com/attack.html
                │
                ▼
         Compare against
         trusted origin
                │
                ▼
             mismatch
                │
                ▼
            ❌ Reject

However, Referer is a meaningfully weaker signal than Origin and should generally not be relied upon as the primary CSRF defense.

The main problem is that the header can legitimately be absent or reduced. Users, browsers, extensions, privacy tools, and site policies can suppress or limit referrer information. For example, Referrer-Policy: no-referrer causes no Referer header to be sent, while strict-origin sends only the origin rather than the full referring URL. Other policy settings can similarly reduce the amount of information available.

This creates an important distinction:

Referer present
      │
      ├── Trusted origin ──► potentially acceptable
      │
      └── Unexpected origin ──► reject

Referer absent
      │
      ├── Could be an attack
      │
      └── Could be legitimate privacy behavior

Consequently, an application that blindly rejects every request without a Referer can break legitimate traffic. Conversely, treating a missing Referer as automatically trusted removes much of the value of the check.

The central principle is: Referer can provide useful evidence about where a request originated, but its absence or reduction is legitimate in normal browser operation. It is therefore best used as a supplementary signal, not as the sole mechanism protecting state-changing requests.

5

Remediation

Secure API Design

🛡️

Remediation

Reserve GET strictly for safe, read-only operations and never use it for state changes. This eliminates the GET-based CSRF surface, rather than relying on tokens or cookie attributes to protect an unsafe method.

For state-changing API requests, require a request characteristic that a plain cross-origin HTML form cannot reproduce, such as a custom header or an appropriate API-specific request mechanism. For example, requiring a header such as X-Requested-With can provide an additional barrier for APIs because a simple HTML form cannot set arbitrary custom headers. This should be treated as an additional layer rather than a replacement for proper CSRF validation, particularly because the header itself is not a secret and non-browser clients can construct it.

For the highest-impact actions, require fresh proof of user intent where appropriate — for example, re-entering the current password, completing a recent MFA challenge, or using another strong reauthentication mechanism for actions such as changing a password, changing the account email address, or modifying sensitive payment information. This creates another independent barrier: even if an attacker manages to trigger the primary state-changing request, the action still requires a credential or authentication factor the attacker's page does not possess.

                    Sensitive action
                          │
          ┌───────────────┼───────────────┐
          ▼               ▼               ▼
      Web form         JSON API       Other client
          │               │               │
          ▼               ▼               ▼
       CSRF token      CSRF token      Appropriate
       + Origin        + Origin        request controls
          │               │               │
          └───────────────┼───────────────┘
                          ▼
                  Same authorization
                    and validation

You've completed Cross Site Request Forgery

Great work — explore other topics to keep learning.