Skip to content
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

Initial Content for the W3C WebAppSec WG Mitigations Wiki #639

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions mitigation-guidance/COOP/breakages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Understanding COOP Breakages

COOP can break things, but it is relatively rare and easy to diagnose. COOP can only cause a breakage if there is a popup involved (see the [FAQ entry "What counts as a popup?"](./faq.md)). So if there is no popup involved, then COOP is not the root cause of the breakage.

If you used COOP's report-only mode before enabling enforcement, and something has broken from a popup, it is likely one of the three COOP reporting gaps described in the "Coop Reporting Gaps" section. Try to understand the breakage and whether or not it could fall into any of those gaps.

Another good first step when debugging a breakage is to change the COOP policy to `same-origin-allow-popups` and see whether this fixes it. Oftentimes this policy is necessary, and it represents only a minimal weakening of security.

One final noteworthy bit here is that enforcing COOP can change the behavior of `window.open` in two different ways:

1. If `window.open` is called from an iframe and the parent page enforces `COOP: same-origin`, then `window.open` will return `null`. This is indistinguishable from how `window.open` behaves if opening the popup is blocked, yet in this case the popup is opened.
2. Otherwise, the return `window` object will act as if it is pointed to a closed popup. This means the `closed` attribute will be true, and calling any of the methods or setting any fields will do nothing.
Binary file added mitigation-guidance/COOP/coop_from_openee.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mitigation-guidance/COOP/coop_from_opener.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mitigation-guidance/COOP/coop_to_openee.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mitigation-guidance/COOP/coop_to_opener.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions mitigation-guidance/COOP/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# FAQ

## What benefit does same-origin have over same-origin-allow-popups?

A significant benefit! We generally recommend that sites enforce a COOP policy of `same-origin` if possible. Suppose that your site, `example.com` is a social network. If a user receives a message from someone else, they can click on a link and it will open the link in a popup. If your site uses `same-origin-allow-popups` then that opened site gets a reference to your site's `window` object and thus can still do many XS-Leak attacks.

## What about restrict-properties?

We generally recommend thinking about restrict-properties as a relaxation compared to same-origin, but a reasonable one that sites can use if necessary. For example, if you have a specific page that needs to be opened in a popup, consider using restrict-properties to protect it. This provides more protections than same-origin-allow-popups and also makes it possible to achieve cross-origin isolation. The one downside to using restrict-properties is that it is currently a Chromium-only feature.

## What counts as a popup?

For the purposes of COOP, a popup is a new tab or a new window that is created via `window.open` or setting a `target="foo"` attribute on an anchor tag. Note that browser-created modals (like `alert` and `confirm`) and HTML modals overlaid on top of an existing page are not popups.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions mitigation-guidance/COOP/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Cross-Origin Opener Policy (COOP)

[Cross Origin Opener Policy (COOP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) is an isolation mechanism that can be used to protect a site's top level `window` object from third-party sites. This defends against [Tabnabbing](https://en.wikipedia.org/wiki/Tabnabbing) and many [XS-Leaks](https://xsleaks.dev/). COOP can also be combined with [COEP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) in order to achieve process-isolation and access additional powerful web APIs. See [this web.dev article](https://web.dev/coop-coep/) for more background information and an introduction to defending your site with COOP.

## Table of Contents

- [Rolling out COOP](./rollouts.md)
- [Understanding COOP Breakages](./breakages.md)
- [FAQ](./faq.md)
Binary file added mitigation-guidance/COOP/redirect_breakages.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
149 changes: 149 additions & 0 deletions mitigation-guidance/COOP/rollouts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Rolling out COOP

## Enabling COOP Report-Only

COOP supports a report-only mode that can be configured via a `Cross-Origin-Opener-Policy-Report-Only` header. This report-only mode can be used to find which parts of your site depend on either opening and interacting with popups or being opened in a popup and interacting with the opener. To configure COOP reports to be sent to your report collector, set the response headers:

```
cross-origin-opener-policy: same-origin; report-to="myReportingGroupName"
report-to: {"group":"myReportingGroupName","max_age":2592000,"endpoints":[{"url":"https://example.com/reports-collector"}]}
```

Note: There are a number of different existing report collectors including report-uri.com, uriports.com, and [this sample OSS implementation on Glitch.](https://glitch.com/edit/#!/reporting-endpoint)

## Understanding COOP Reports

This will cause browsers to send information about popup interactions to `https://example.com/reports-collector`. For example, if `foo.example` opened `bar.example/foo` in a popup and sent it a message via `postMessage`, you would receive a report like:

```
{
"age":6,
"body":{
"disposition": "reporting",
"effectivePolicy": "same-origin",
"property": "postMessage",
"referrer": "foo.example",
"type":"access-to-coop-page-from-opener"
},
"type":"coop",
"url":"bar.example/foo",
"user_agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"
}
```

Note that this report has a number of useful pieces of information in it. It tells you:

1. The `url` of the page that was opened in a popup (the **openee**)
2. The `referrer`, which tells you what the third-party site was (the **opener**)
3. The `property` that was accessed
4. The `type` of violation

This last field, the `type` field is one of the most important. It tells you that this was an access to a COOP page (aka the page that is setting the COOP report-only header) from the opener of that page (aka that the COOP page is the one in a popup). In this case, if this is something that your site needs to support, you would need to ensure that `bar.example/foo` sets a COOP policy of `unsafe-none`.

There are 6 different `type`s that a COOP report may specify. The `type` tells you what policy change is necessary in order to allow the behavior that triggered the report.

### Access to COOP Page From Openee

This violation type means that a COOP page opened a cross-origin page that tried to access a field on its opener, e.g. `window.opener.field`. One common way this can happen is if you open a popup that sends a message to your page.

![Access to COOP Page from Openee](./coop_from_openee.png)

This violation type can be fixed by setting `same-origin-allow-popups` on the COOP page that opened the window.

### Access from COOP Page To Openee

This violation type means that a COOP page opened a cross-origin page and accessed a field of that window. For example, `window.open(other_site).field`. One common way this can happen is if you open a popup and send a message to it via postMessage.

![Access from COOP Page to Openee](./coop_to_openee.png)

This violation type can be fixed by setting `same-origin-allow-popups` on the COOP page that opened the window.

### Access to COOP Page From Opener

This violation type means that a page opened a cross-origin COOP page and tried to access a field on its opener, e.g. `window.open(other_site_with_coop).field`. One common way this can happen is if you open a popup and send a message to it via postMessage.

![Access to COOP Page from Opener](./coop_from_opener.png)

This violation type can be fixed by setting `unsafe-none` on the page that is being opened.

### Access From COOP Page To Opener

This violation type means that a page opened a cross-origin COOP page that did `window.opener.field`. One common way this can happen is if you open a popup that sends a message to your page.

![Access from COOP Page from Opener](./coop_to_opener.png)

This violation type can be fixed by setting `unsafe-none` on the page that is being opened.

### Access To COOP Page From Other

This rarer violation type means that a COOP page was accessed by a cross-origin page that doesn’t have an opener or an openee relationship with the COOP page. This can be thought of as a catchall category. One example of a way this kind of report can be triggered is if a window reference is obtained via `window.open('', 'name_of_window')`.

This violation type can be fixed by setting `unsafe-none` on the page that is being accessed.

### Access From COOP Page To Other

This rarer violation type means that a COOP page tried to access a field on another page that it doesn’t have an opener or an openee relationship with. This can be thought of as a catchall category. One example of a way this kind of report can be triggered is if a window reference is obtained via `window.open('', 'name_of_window')`.

This violation type can be fixed by setting `unsafe-none` on the page that is doing the access.

## Common Difficulties

### Coop Reporting Gaps

COOP's report-only mode is meant to allow you to find the places on your site that depend on interactions with popups. It will report almost all of these interactions, but there are a few edge cases under which a site could trigger no COOP reports, yet still break when enforcement is enabled. These are relatively rare edge cases, but human review is the only way to ensure that a site does not fall into any of these gaps.

#### Case 1: Iframe Window Interactions

If a page enables COOP, all iframes on that page also get COOP enforced. This means that if a page enables COOP and it embeds a page that needs to open popups and interact with them, it may break. See this diagram:

![Iframe window interactions](./iframe_window_interactions.png)

#### Case 2: Redirect Breakages

If:

1. A page enables COOP enforcement
2. That page redirects to a page without COOP enforcement
3. Some other service `window.open`s the page with COOP enforcement
4. That service then tries to use the window reference for cross-origin communication

Then things can break. See this diagram:

![Redirect breakages](./redirect_breakages.png)

This is most likely to occur in terms of login flows where a popup is often redirected to a final page that needs to use `postMessage`. In this case, every piece of the redirect chain must enforce a policy of `unsafe-none`.

#### Case 3: Iframe Sandbox Breakages

If:

1. A page contains an iframe with `sandbox="allow-popups"` but without `allow-popups-to-escape-sandbox`
2. That iframe opens a popup to `example.com/endpoint`
3. `example.com/endpoint` enforces COOP

Then the opened popup will show a network error page with the error `CoopSandboxedIFrameCannotNavigateToCoopPage`. See this diagram:

![Iframe sandbox breakages](./iframe_sandbox_breakages.png)

### Atomic Per User Rollouts

Due to some quirks of how COOP works, it must be rolled out atomically for a given user. So when enabling COOP enforcement ensure that a user will never fall into a scenario where one request has COOP enforced, and the next one doesn't. Read on to find out why!

In addition to restricting communication between two tabs, COOP also affects how a browser allocates Browser Context Groups (aka BCGs, a concept similar to processes). Separate tabs/windows can only interact with each other if they are in the same BCG.

Example: Suppose that we're rolling out COOP for a service where `example.com/foo` opens a popup to `example.com/bar`. Since all popups are `same-origin`, we can enforce `COOP: same-origin` on this service. But, suppose that during the rollout a user's request to `example.com/foo` hits prod and `example.com/bar` hits canary. In this case, a page with an implicit policy of `unsafe-none` opens a popup to an endpoint that has a policy of `same-origin`. This triggers a BCG switch and thus prevents the two pages from interacting.

Because of this, if a service uses any `same-origin` popups, it is essential that COOP is forced atomically for a given user. As our data provides no way of tracking same-origin popups, we're forced to assume that every service uses `same-origin` popups.

**Note:** If you know that your service does not need to interact with any `same-origin` popups, then it is safe to roll out COOP gradually.

### Client-side navigation

If your site uses client-side navigation, special care needs to be taken when handling `same-origin-allow-popups` exemptions. Suppose that `example.com/foo` needs to open and interact with popups. So you might think you should just ensure that `/foo` sets `same-origin-allow-popups` and that the rest of the site can set `same-origin`. But, if `example.com` uses client-side navigation then the user can go to `example.com`, get a `COOP: same-origin` header, and then client-side navigate to `/foo`. This would happen without an HTTP request to `/foo` and thus the user would end up on `/foo` without having seen the `COOP: same-origin-allow-popups` header. Thus, if your site uses client-side navigation, if one page needs to open popups then the entire site needs to use the relaxed `same-origin-allow-popups` policy value.

### Common Noise

COOP reports are generally not noisy, most of the time a reported violation is a real concern. There are a few common classes of violation reports that are worth considering ignoring:

1. Reports from extensions. You may see reports where the URL or the referrer is a `chrome-extension://` URL. Some chrome extensions interact with pop ups in a way that COOP will break. It is up to you whether or not breaking this is ok for your service.
2. Reports from third party sites opening your site in a popup and monitoring whether it has been closed. Many websites on the internet track whether a popup has been closed or not. Oftentimes this is not something that your service intends to support and thus it is often okay to ignore these violations.
11 changes: 11 additions & 0 deletions mitigation-guidance/CSP/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# FAQ

## How does a strict CSP work in browsers that don't support CSP3?

When you use a nonce-based policy with strict-dynamic, compatible browsers only execute scripts whose nonce attribute matches the value set in the policy header, as well as scripts dynamically added to the page by scripts with the proper nonce.

* The policy is also backwards compatible with browsers that don't support CSP3:
Browsers that do not support the CSP3 standard ignore `strict-dynamic`. These browsers see `script-src 'nonce-...' https: http:` which provides minimal protection against XSS vulnerabilities but allows the application to function.
* Browsers that do not support the CSP2 standard ignore 'strict-dynamic' and 'nonce-*'. These browsers see `script-src 'unsafe-inline' https: http:` which does not provide any protection against XSS vulnerabilities but allows the application to function normally.

See [here](https://caniuse.com/?search=strict-dynamic) for up-to-date information on which browsers support strict-dynamic.
7 changes: 7 additions & 0 deletions mitigation-guidance/CSP/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Content Security Policy (CSP)

[CSP (Content Security Policy)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is a security feature that can be used to mitigate XSS in your application. See [this web.dev article](https://web.dev/strict-csp/) for more background information and an introduction to defending your site with CSP.

## Table of Contents

- [FAQ](./faq.md)
7 changes: 7 additions & 0 deletions mitigation-guidance/FM/breakages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Understanding Fetch Metadata (FM) Breakages

In order to make Fetch Metadata breakages easy to diagnose, we recommend including metadata on why the response was rejected in the 403 response page (either in the body or in the response headers). This makes it so that checking if a breakage is caused by Fetch Metadata is as simple as checking whether there are any 403 responses rejected by your policy.

Additionally, it is recommended to exempt 404 pages from your Fetch Metadata policies. Suppose that a page includes `<img src=other.com/photos/myurl>` and that `other.com/photos/myurl` is exempted from RIP since it is meant to be referenced cross-site. If the photo is not found, the site responds with a 404 error. If RIP is enforced for the 404 page, the 404 error will be converted to a potentially confusing 403 error.

Since Fetch Metadata policies are enforced server-side, it is very easy to add centralized logging and monitoring of how Fetch Metadata policies are affecting your application. For example, an application could trigger an alert if more than 1% of requests to a given URL are getting blocked by Fetch Metadata policies. This is useful for both detecting breakages and understanding the impact of any breakages.
9 changes: 9 additions & 0 deletions mitigation-guidance/FM/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# FAQ

## Is deploying Resource Isolation Policy enough to protect from CSRF and XSSI vulnerabilities?

It depends on which browsers your application supports. The latest versions of Chrome, Firefox, and Safari all support Fetch Metadata headers so RIP can be used as a primary defense in these browsers. But some other browsers (and older browser versions) don’t support Fetch Metadata headers, so we still recommend adopting other defenses and using RIP as a secondary defense. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Site#browser_compatibility) for more information on browser compatibility.

## Does this break browser extensions accessing resources from my application?

No, it shouldn't. When browser extensions request a resource from a site they have `host` permissions to access, the request is sent as `Sec-Fetch-Site: none` and thus it will not be blocked by any of these isolation policies.
9 changes: 9 additions & 0 deletions mitigation-guidance/FM/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Fetch Metadata (FM)

Fetch Metadata headers allow your service to block requests coming from unexpected contexts. FM isolation policies can protect your service from XSRF, [Spectre](https://developers.google.com/web/updates/2018/02/meltdown-spectre), and many [XS-Leaks](https://xsleaks.dev). See [this web.dev article](https://web.dev/fetch-metadata/) for more background information and an introduction to defending your site with Fetch Metadata.

## Table of Contents

- [Rolling out FM](./rollouts.md)
- [Understanding FM Breakages](./breakages.md)
- [FAQ](./faq.md)
Loading