Cross-Origin-Opener-Policy (COOP) to prevent attacks from popups
origins
An origin is a URL from the browser’s point of view. Two URLs have the same origin if the following components of the URL match:
- the scheme (i.e.:
httporhttps) - the TLD (
.com) - the domain (
example.com) - the subdomain (
www.) - the port
Notably, paths (/some/path) and querystrings (?key=value) and fragments (#someid) are not part of the origin.
same-origin policy
The same-origin policy is a security mechanism used by browsers to restrict how resources loaded from one orgin can interact with resources loaded from another. This is why cross-origin requests are blocked unless Corss Origin Resource Sharing (CORS) is enabled.
Aside from fetch(), there are other JavaScript APIs that interact with different documents, like iframe.contentWindow (which returns
the Window object of an iFrame). If documents are of the same-origin, then you have direct access to the other Window. But if they
are not, you can only access
a limited number of properties and methods
of the Window. Despite this restriction, there are still attacks that use these APIs to leak information across origins.
vulnerabilities
Cross-site leaks ("
XS-Leaks") attack the side-channels built into web platforms to infer information about other sites.
For example, window.Length returns the number of iframes in a document. Consider a scenario where this number changes based on the properties
of the user. This would make it a property that can be abused. Facebook
patched a bug that
abused this property.
Cross-Origin-Opener-Policy
Cross-Origin-Opener-Policy is a security header that can be returned in HTTP responses which enables additional protections for when different documents
call window.open on your site. It has three possible values:
unsafe-none— the default (unsafe) valuesame-origin— the most safe valuesame-origin-allow-popups— a middle ground
Consider two different sites:
- The opener calls
window.Open()which returns aWindowobject that references the opened site. - The opened site can use the
window.openerproperty to reference theWindowobject of the opener.
Both sites can set different values for COOP. The combination of the two values controls whether or not the two documents are in the same browsing context. If they are in different browsing contexts, then:
- In the opened,
window.openerisnull. - in the opener,
window.open()returns “default” values for some properties.
scenarios
Consider two web apps:
- Serves an
Index.htmlthat contains a button which returnswindow.open()in open a popup in #2. - Serves a
Popup.htmlwhich attempts to readwindow.opener.
Scenario 1
- Both apps have the same origin.
- Result:
- The
Cross-Origin-Opener-Policyon either app is ignored. - In the opener:
window.closedreturnsfalse(the correct value). - In the opened:
window.openerreturns the “real”Windowobject.
- The
Scenario 2 This scenario is the least secure.
- The apps have different origins.
- Both apps set
Cross-Origin-Opener-Policy: unsafe-none(or don’t set the header at all). - Result:
window.openeris available in the popup.- In the opener:
window.closedreturnsfalse(the correct value). - In the opened:
window.openerreturns the realWindowobject.
Scenario 3 This scenario is the most secure.
- The apps have different origins.
- One of the apps sets
Cross-Origin-Opener-Policy: same-origin. - Result:
- In the opener:
window.closedreturnstrue(the incorrect value). - In the opened:
window.openerretrunsnull.
- In the opener:
When either app uses same-origin, that app opts out of context sharing, and without context sharing, the result is the same regardless of which app opts out.
Scenario 4
- The apps have different origins.
- One of the apps sets
Cross-Origin-Opener-Policy: same-origin-allow-popups. - Result:
- If the opener uses
unsafe-none(or omits the header), the apps share browsing context. - If the opener uses anything else, the browsing contexts are isolated.
- If the opened uses
unsafe-none, the browsing contexts are isolated.
- If the opener uses
Summary of scenarios:
| Opener COOP value | Opened COOP value | Context is… |
|---|---|---|
unsafe-none / missing | unsafe-none / missing | Shared |
unsafe-none / missing | same-origin-allow-popups | Isolated |
unsafe-none / missing | same-origin | Isolated |
same-origin-allow-popups | unsafe-none / missing | Shared |
same-origin-allow-popups | same-origin-allow-popups | Isolated |
same-origin-allow-popups | same-origin | Isolated |
same-origin | unsafe-none / missing | Isolated |
same-origin | same-origin-allow-popups | Isolated |
same-origin | same-origin | Isolated |
Cross-Origin-Opener-Policy-Report-Only
This header “simulates” the COOP policy and sends any violations via the browser’s reporting API.