-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Update Fetch Metadata positioning #1875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mkhanas
wants to merge
37
commits into
OWASP:master
Choose a base branch
from
mkhanas:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+126
−89
Open
Changes from 17 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
435a7d5
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 3ae17e8
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 0920907
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 0c2aa20
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 8d1a394
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas ae616bd
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
jmanico 8cc3255
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 8baf8d4
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 86fc26b
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas c3579b5
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 68310fc
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas a6d7336
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas d216055
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas a6ccd2c
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
jmanico c1b4d3f
Merge branch 'OWASP:master' into master
mkhanas ce48f47
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas ed608c5
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 189cb71
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 9813b91
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas f3b2ab4
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 49d7111
Merge branch 'OWASP:master' into master
mkhanas 1adef8a
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas a4e6e73
Merge branch 'OWASP:master' into master
mkhanas 8465295
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas f5f08c5
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 278e8f2
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 8dbbbed
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 0193cd8
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas b7071c9
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 7c92749
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas b0aae7d
Merge branch 'OWASP:master' into master
mkhanas e2841e5
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas d88c962
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas e5a586e
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 2c6dbfa
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 6c81728
Update cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas 17e5789
Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
mkhanas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,8 @@ In short, the following principles should be followed to defend against CSRF: | |
|
|
||
| - **See the OWASP [XSS Prevention Cheat Sheet](Cross_Site_Scripting_Prevention_Cheat_Sheet.md) for detailed guidance on how to prevent XSS flaws.** | ||
| - **First, check if your framework has [built-in CSRF protection](#use-built-in-or-existing-csrf-implementations-for-csrf-protection) and use it** | ||
| - **If the framework does not have built-in CSRF protection, add [CSRF tokens](#token-based-mitigation) to all state changing requests (requests that cause actions on the site) and validate them on the backend** | ||
| - **If the framework does not have built-in CSRF protection, add [CSRF tokens](#token-based-mitigation) to all state-changing requests (requests that cause actions on the site) and validate them on the backend.** | ||
| - **If your software is intended to be used only on modern browsers, you may rely on [Fetch Metadata headers](#fetch-metadata-headers) to block cross-site state-changing requests, so long as you use the fallback options detailed below.** | ||
| - **Stateful software should use the [synchronizer token pattern](#synchronizer-token-pattern)** | ||
| - **Stateless software should use [double submit cookies](#alternative-using-a-double-submit-cookie-pattern)** | ||
| - **If an API-driven site can't use `<form>` tags, consider [using custom request headers](#employing-custom-request-headers-for-ajaxapi)** | ||
|
|
@@ -25,13 +26,16 @@ In short, the following principles should be followed to defend against CSRF: | |
| - **Do not use GET requests for state changing operations.** | ||
| - **If for any reason you do it, protect those resources against CSRF** | ||
|
|
||
| ## Token-Based Mitigation | ||
| ### Use Built-In Or Existing CSRF Implementations for CSRF Protection | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The [synchronizer token pattern](#synchronizer-token-pattern) is one of the most popular and recommended methods to mitigate CSRF. | ||
| Before building a custom token or Fetch-Metadata implementation, check whether your framework or platform already provides CSRF protection you can use. Built-in defenses are generally preferable because they’re maintained by the framework authors and reduce the risk of subtle implementation mistakes. For example: | ||
|
|
||
| ### Use Built-In Or Existing CSRF Implementations for CSRF Protection | ||
| - .NET can use [built-in protection](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1) to add tokens to CSRF vulnerable resources. If you choose to use this protection, .NET makes you responsible for proper configuration (such as key management and token management). | ||
| - Starting from [1.25](https://pkg.go.dev/net/[email protected]), Go developers can rely on the built-in [CrossOriginProtection](https://pkg.go.dev/net/[email protected]#CrossOriginProtection) type. It implements a Fetch-Metadata-based CSRF defense (including validation of Sec-Fetch-Site and related headers) directly in the standard library. | ||
|
|
||
| Since synchronizer token defenses are built into many frameworks, find out if your framework has CSRF protection available by default before you build a custom token generating system. For example, .NET can use [built-in protection](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1) to add tokens to CSRF vulnerable resources. If you choose to use this protection, .NET makes you responsible for proper configuration (such as key management and token management). | ||
| ## Token-Based Mitigation | ||
|
|
||
| The [synchronizer token pattern](#synchronizer-token-pattern) is one of the most popular and recommended methods to mitigate CSRF. | ||
|
|
||
| ### Synchronizer Token Pattern | ||
|
|
||
|
|
@@ -151,6 +155,95 @@ Since an attacker is unable to access the cookie value during a cross-site reque | |
|
|
||
| Though the Naive Double-Submit Cookie method is simple and scalable, it remains vulnerable to cookie injection attacks, especially when attackers control subdomains or network environments allowing them to plant or overwrite cookies. For instance, an attacker-controlled subdomain (e.g., via DNS takeover) could inject a matching cookie and thus forge a valid request token. [This resource](https://owasp.org/www-chapter-london/assets/slides/David_Johansson-Double_Defeat_of_Double-Submit_Cookie.pdf) details these vulnerabilities. Therefore, always prefer the _Signed Double-Submit Cookie_ pattern with session-bound HMAC tokens to mitigate these threats. | ||
|
|
||
| ## Fetch Metadata headers | ||
mkhanas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Fetch Metadata request headers provide extra context about how an HTTP request was made, and how the resource will be used, enabling servers to reject suspicious cross-site requests. Servers can use these headers — most importantly `Sec-Fetch-Site` — as a lightweight and reliable method to block obvious cross-site requests. See the [Fetch Metadata specification](https://www.w3.org/TR/fetch-metadata/) for details. | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Because some legacy browsers may not send `Sec-Fetch-*` headers, a fallback to [standard origin verification](#using-standard-headers-to-verify-origin) headers **is a mandatory requirement** for any Fetch Metadata implementation. `Sec-Fetch-*` [is supported](https://caniuse.com/?search=sec-fetch-site) in all browsers since March 2023 (with the exception of IE as it no longer receives updates and does not support `Sec-Fetch-*` headers). | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| The Fetch Metadata request headers are: | ||
mkhanas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| - Sec-Fetch-Site — the primary signal for CSRF protection. It indicates relationship between request initiator’s origin and it's target's origin: `same-origin`, `same-site`, `cross-site`, or `none`. | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - Sec-Fetch-Mode, Sec-Fetch-Dest, Sec-Fetch-User — additional headers that provide context about the request (such as the request mode, destination type, or whether it was triggered by a user navigation). More details are available in the [MDN documentation](https://developer.mozilla.org/en-US/docs/Glossary/Fetch_metadata_request_header). | ||
|
|
||
| If any of headers above contain values not listed in the specification, in order to support forward-compatibility, servers should ignore those headers. | ||
|
|
||
| ### Ease of use | ||
|
|
||
| Unlike [synchronizer tokens](#synchronizer-token-pattern) or [double-submit patterns](#alternative-using-a-double-submit-cookie-pattern) — which require additional client/server coordination and are easy to misimplement — Fetch Metadata checks are straightforward to implement correctly. They typically require only a small amount of server-side logic (inspect Sec-Fetch-Site, optionally refine with Sec-Fetch-Mode/Sec-Fetch-Dest) and no client changes. That simplicity reduces complexity, making the approach attractive for many applications. | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Browser compatibility | ||
|
|
||
| Fetch Metadata request headers are supported in most modern browsers on both desktop and mobile (Chrome, Edge, Firefox, Safari 16.4+, and even in webviews on both iOS and Android), with [over 98% global coverage](https://caniuse.com/mdn-http_headers_sec-fetch-site). For compatibility detail, see the [browser support table](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-Fetch-Site#browser_compatibility). | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| For the rare cases of outdated or embedded browsers that lack `Sec-Fetch-*` support, a fallback to [standard origin verification](#using-standard-headers-to-verify-origin) should provide the required coverage. If this is acceptable for your project, consider prompting users to update their browsers, as they are running on outdated and potentially insecure versions. | ||
|
|
||
| ### How to treat Fetch Metadata headers on the server-side | ||
mkhanas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| `Sec-Fetch-Site` is the most useful Fetch Metadata header for blocking CSRF-like cross-origin requests and should be the primary signal in a Fetch-Metadata-based policy. Use other Fetch Metadata headers (`Sec-Fetch-Mode`, `Sec-Fetch-Dest`, `Sec-Fetch-User`) to further refine or tailor policies to your application's needs (for example, allowing top-level navigation requests or permitting specific Dest values for resource endpoints). | ||
| **Policy (high level)** | ||
|
|
||
| 1. If `Sec-Fetch-Site` is present: | ||
| 1.1. Treat cross-site as untrusted for state-changing actions. By default, reject non-safe methods (POST / PUT / PATCH / DELETE) when `Sec-Fetch-Site: cross-site`. | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```JavaScript | ||
| const SAFE = new Set(['GET','HEAD','OPTIONS']); | ||
| const site = req.get('Sec-Fetch-Site'); // e.g. 'cross-site','same-site','same-origin','none' | ||
|
|
||
| if (site === 'cross-site' && !SAFE.has(req.method)) { | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return false; // forbid this request | ||
| } | ||
| ``` | ||
|
|
||
| 1.2. Allow `same-origin`. Treat `same-site` as allowed only if your threat model trusts sibling subdomains; otherwise handle `same-site` conservatively (for example, require additional validation). | ||
|
|
||
| ```JavaScript | ||
| const trustSameSite = false; // set true only if you trust sibling subdomains | ||
|
|
||
| if (site === 'same-origin') { | ||
| return true; | ||
| } else if (site === 'same-site') { | ||
| // handle same-site separately so the subcondition is clearly scoped to same-site | ||
| if (!trustSameSite && !SAFE.has(req.method)) { | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return false; // treat same-site as untrusted for state-changing methods | ||
| } | ||
| return true; | ||
| } | ||
| ``` | ||
|
|
||
| 1.3. Allow none for user-driven top-level navigations (bookmarks, typed URLs, explicit form submits) where appropriate. | ||
|
|
||
| 2. If `Sec-Fetch-*` headers are absent: choose a fallback based on risk and compatibility requirements: | ||
| 2.1. Fail-safe (recommended for sensitive endpoints): treat absence as unknown and block the request. | ||
| 2.2. Fail-open (compatibility-first): fallback to other security measure ([standard origin verification](#using-standard-headers-to-verify-origin), CSRF tokens, and/or require additional validation). | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| 3. Additional options | ||
| 3.1 To ensure that your site can still be linked from other sites, you have to allow simple (HTTP GET) top-level navigation. | ||
|
|
||
| ```JavaScript | ||
| if (req.get('Sec-Fetch-Mode') === 'navigate' && | ||
| req.method === 'GET' && | ||
| req.get('Sec-Fetch-Dest') !== 'object' && | ||
| req.get('Sec-Fetch-Dest') !== 'embed') { | ||
| return true; // Allow this request | ||
| } | ||
| ``` | ||
|
|
||
| 3.2 Whitelist explicit cross-origin flows. If certain endpoints intentionally accept cross-origin requests (CORS JSON APIs, third-party integrations, webhooks), explicitly exempt those endpoints from the global Sec-Fetch deny policy and secure them with proper CORS configuration, authentication, and logging. | ||
|
|
||
| ### Requirements | ||
|
|
||
| - Your application must be served over trustworthy URLs. Fetch Metadata request headers are only sent to [potentially trustworthy URLs](https://www.w3.org/TR/secure-contexts/#is-url-trustworthy). In practice, this includes `https`, `wss`, `file`, and `localhost` (including `127.0.0.0/8` and `::1/128`). See the [W3C Secure Contexts spec](https://www.w3.org/TR/secure-contexts/#is-origin-trustworthy) for full details. | ||
| - HTTPS must be enforced across the entire application. This ensures consistent inclusion of Fetch Metadata headers. Enabling [HTTP Strict Transport Security (HSTS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security) helps achieve this by automatically upgrading all HTTP requests to HTTPS. | ||
| - [Safe HTTP methods](https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP) must not be used for state-changing requests. | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Rollout & testing recommendations | ||
|
|
||
| - Include an appropriate `Vary` header, in order to ensure that caches handle the response appropriately. For example, `Vary: Accept-Encoding, Sec-Fetch-Site`. See more [Fetch Metadata specification](https://w3c.github.io/webappsec-fetch-metadata/#vary). | ||
mkhanas marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| - Start in “log only” mode. Record requests that would be blocked and review for false positives before enforcing. This is the safest way to discover legitimate flows that need whitelisting. | ||
| - Monitor UA coverage. Track which user agents include `Sec-Fetch-*` and which don’t; ensure your fallback logic covers missing-header cases. Use metrics to decide when to enforce stricter policies. | ||
| - Document exceptions. Keep an explicit list of endpoints whitelisted for cross-origin access. | ||
|
|
||
| ## Disallowing simple requests | ||
|
|
||
| When a `<form>` tag is used to submit data, it sends a ["simple" request](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) that browsers do not designate as "to be preflighted". These "simple" requests introduce risk of CSRF because browsers permit them to be sent to any origin. If your application uses `<form>` tags to submit data anywhere in your client, you will still need to protect them with alternate approaches described in this document such as tokens. | ||
|
|
@@ -368,89 +461,6 @@ Cookie prefixes [are supported by all major browsers](https://developer.mozilla. | |
|
|
||
| See the [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives) and [IETF Draft](https://tools.ietf.org/html/draft-west-cookie-prefixes-05) for further information about cookie prefixes. | ||
|
|
||
| ### Use Fetch Metadata headers to verify nature of the request | ||
|
|
||
| Fetch Metadata request headers provide extra context about how an HTTP request was made, and how the resource will be used, enabling servers to reject suspicious cross-site requests. Servers can use these headers — most importantly `Sec-Fetch-Site` — as a lightweight method to block obvious cross-site requests. See the [Fetch Metadata specification](https://www.w3.org/TR/fetch-metadata/) for details. | ||
|
|
||
| It is important to note that Fetch Metadata headers should be implemented as an additional layer defense in depth concept. This attribute should not replace a CSRF tokens (or equivalent framework protections). | ||
|
|
||
| The Fetch Metadata request headers are: | ||
|
|
||
| - Sec-Fetch-Site — indicates relationship between request initiator’s origin and it's target's origin: `same-origin`, `same-site`, `cross-site`, or `none`. | ||
| - Sec-Fetch-Mode — indicates the request's [mode](https://fetch.spec.whatwg.org/#concept-request-mode)(e.g., `navigate`, `no-cors`, `cors`, `same-origin`, and `websocket`), which allows to distinguish between requests originating from a user navigating between HTML pages, and requests to load images and other resources. | ||
| - Sec-Fetch-Dest — indicates the [destination](https://fetch.spec.whatwg.org/#concept-request-destination) for the requested resource (e.g., `document`, `image`, `script`, etc.). | ||
| - Sec-Fetch-User — present only for navigation requests initiated by user. When sent value is `?1`, meaning `true`. | ||
|
|
||
| If any of headers above contain values not listed in the specification, in order to support forward-compatibility, servers should ignore those headers. | ||
|
|
||
| Browser compatability: Fetch Metadata request headers are supported in most modern browsers on both desktop and mobile (Chrome, Edge, Firefox, Safari 16.4+, and even in webviews on both iOS and Android). For compatibility detail, see the [browser support table](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-Fetch-Site#browser_compatibility). | ||
|
|
||
| #### How to treat Fetch Metadata headers on the server-side | ||
|
|
||
| Sec-Fetch-Site is the most useful Fetch Metadata header for blocking CSRF-like cross-origin requests and should be the primary signal in a Fetch-Metadata-based policy. Use other Fetch Metadata headers (Sec-Fetch-Mode, Sec-Fetch-Dest, Sec-Fetch-User) to further refine or tailor policies to your application (for example, allowing navigate mode top-level requests or permitting specific Dest values for resource endpoints). | ||
| **Policy (high level)** | ||
|
|
||
| 1. If Sec-Fetch-Site is present: | ||
| 1.1. Treat cross-site as untrusted for state-changing actions. By default, reject non-safe methods (POST / PUT / PATCH / DELETE) when `Sec-Fetch-Site: cross-site`. | ||
|
|
||
| ```JavaScript | ||
| const SAFE = new Set(['GET','HEAD','OPTIONS']); | ||
| const site = req.get('Sec-Fetch-Site'); // e.g. 'cross-site','same-site','same-origin','none' | ||
|
|
||
| if (site === 'cross-site' && !SAFE.has(req.method)) { | ||
| return false; // forbid this request | ||
| } | ||
| ``` | ||
|
|
||
| 1.2. Allow `same-origin`. Treat `same-site` as allowed only if your threat model trusts sibling subdomains; otherwise handle `same-site` conservatively (for example, require additional validation). | ||
|
|
||
| ```JavaScript | ||
| const trustSameSite = false; // set true only if you trust sibling subdomains | ||
|
|
||
| if (site === 'same-origin') { | ||
| return true; | ||
| } else if (site === 'same-site') { | ||
| // handle same-site separately so the subcondition is clearly scoped to same-site | ||
| if (!trustSameSite && !SAFE.has(req.method)) { | ||
| return false; // treat same-site as untrusted for state-changing methods | ||
| } | ||
| return true; | ||
| } | ||
| ``` | ||
|
|
||
| 1.3. Allow none for user-driven top-level navigations (bookmarks, typed URLs, explicit form submits) where appropriate. | ||
|
|
||
| 2. If Sec-Fetch-* headers are absent: choose a fallback based on risk and compatibility requirements: | ||
| 2.1. Fail-safe (recommended for sensitive endpoints): treat absence as unknown and block the request. | ||
| 2.2. Fail-open (compatibility-first): fallback to other security measure (CSRF tokens, validate Origin/Referer, and/or require additional validation). | ||
|
|
||
| 3. Additionall options | ||
| 3.1 To ensure that your site can still be linked from other sites, you have to allow simple (HTTP GET) top-level navigation. | ||
|
|
||
| ```JavaScript | ||
| if (req.get('Sec-Fetch-Mode') === 'navigate' && | ||
| req.method === 'GET' && | ||
| req.get('Sec-Fetch-Dest') !== 'object' && | ||
| req.get('Sec-Fetch-Dest') !== 'embed') { | ||
| return true; // Allow this request | ||
| } | ||
| ``` | ||
|
|
||
| 3.2 Whitelist explicit cross-origin flows. If certain endpoints intentionally accept cross-origin requests (CORS JSON APIs, third-party integrations, webhooks), explicitly exempt those endpoints from the global Sec-Fetch deny policy and secure them with proper CORS configuration, authentication, and logging. | ||
|
|
||
| #### Limitations and gotchas | ||
|
|
||
| - Not universal. Some older browsers, webviews, bots, and non-browser HTTP clients do not send Sec-Fetch-*. Do not assume presence on every request — implement fallbacks. | ||
| - May break legitimate cross-origin integrations. A global Sec-Fetch policy can unintentionally block legitimate CORS or third-party flows; plan explicit whitelisting. | ||
| - One limitation is that Fetch Metadata request headers are only sent to [potentially trustworthy URLs](https://www.w3.org/TR/secure-contexts/#is-url-trustworthy). This means the headers will generally be present for requests to origins whose scheme is `https`, `wss`, or `file`, and for `localhost` (hosts in the `127.0.0.0/8` or `::1/128` ranges). For the full rules and additional edge cases (the algorithm the user agent uses to decide trustworthiness), see the [W3C Secure Contexts spec](https://www.w3.org/TR/secure-contexts/#is-origin-trustworthy). | ||
|
|
||
| #### Rollout & testing recommendations | ||
|
|
||
| - Include an appropriate Vary header [RFC9110], in order to ensure that caches handle the response appropriately. For example, `Vary: Accept-Encoding, Sec-Fetch-Site`. See more [Fetch Metadata specification](https://w3c.github.io/webappsec-fetch-metadata/#vary). | ||
| - Start in “log only” mode. Record requests that would be blocked and review for false positives before enforcing. This is the safest way to discover legitimate flows that need whitelisting. | ||
| - Monitor UA coverage. Track which user agents include Sec-Fetch-* and which don’t; ensure your fallback logic covers missing-header cases. Use metrics to decide when to enforce stricter policies. | ||
| - Document exceptions. Keep an explicit list of endpoints whitelisted for cross-origin access. | ||
|
|
||
| ### User Interaction-Based CSRF Defense | ||
|
|
||
| While all the techniques referenced here do not require any user interaction, sometimes it's easier or more appropriate to involve the user in the transaction to prevent unauthorized operations (forged via CSRF or otherwise). The following are some examples of techniques that can act as strong CSRF defense when implemented correctly. | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.