Cross-Origin-Embedder-Policy: credentialless

A Collection of Interesting Ideas,

Issue Tracking:
whatwg/html topic: coep-credentialless
w3c/ServiceWorker topic: coep-credentialless
Editors:
(Google)
(Google)
(Google)
(Google)
Version History:
WICG/credentiallessness
Obsoletion Notice

COEP:credentialless merged into the [HTML] and [Fetch] specification.
This document is no longer actively maintained, and should not be used as a guide for implementations.

See PR: whatwg/html/6638, whatwg/fetch/1229
Significant sections: HTML: (1) (2) (3) (4) Fetch: (1) (2) (3)


Abstract

Credentialless is a Cross-Origin-Embedder-Policy (COEP) variant. Similarly to require-corp, it can be used to enable cross-origin-isolation. Contrary to require-corp, it is easier to deploy, instead of requiring a Cross-Origin-Resource-Policy (CORP) header for every no-cors subresources, COEP:credentialless is requesting them without credentials.

1. A problem

Sites that wish to continue using SharedArrayBuffer must opt-into cross-origin isolation. Among other things, cross-origin isolation will block the use of cross-origin resources and documents unless those resources opt-into inclusion via either CORS or CORP. This behavior ships today in Firefox, and Chrome aims to ship it as well in 2021H1.

The opt-in requirement is generally positive, as it ensures that developers have the opportunity to adequately evaluate the rewards of being included cross-site against the risks of potential data leakage via those environments. It poses adoption challenges, however, as it does require developers to adjust their servers to send an explicit opt-in. This is challenging in cases where there’s not a single developer involved, but many. Google Earth, for example, includes user-generated content in sandboxed frames, and it seems somewhat unlikely that they’ll be able to ensure that all the resources typed in by all their users over the years will do the work to opt-into being loadable.

Cases like Earth are, likely, outliers. Still, it seems clear that adoption of any opt-in mechanism is going to be limited. From a deployment perspective (especially with an eye towards changing default behaviors), it would be ideal if we could find an approach that provided robust-enough protection against accidental cross-process leakage without requiring an explicit opt-in.

2. A proposal

The goal of the existing opt-in is to block interesting data that an attacker wouldn’t otherwise have access to from flowing into a process they control. It might be possible to obtain a similar result by minimizing the risk that outgoing requests will generate responses personalized to a specific user by extending coep to support a new credentialless mode which strips credentials (cookies, client certs, etc) by default for no-cors subresource requests. Let’s explore that addition first, then look at whether it’s Good Enough to enable cross-origin isolation.

2.1. Subresource requests

In this new COEP variant, cross-origin no-cors subresource requests would be sent without credentials. Specific requests which require credentials can opt-into including them, at the cost of shifting the request’s mode to require a CORS check on the response. This bifurcation between credentiallessness and CORS means either that servers don’t have browser-provided identifiers which could be used to personalize a response (see the isolation section below), or that they explicitly opt-in to exposing the response’s content to the requesting origin.

As an example, consider a developer who wishes to load an image into a context isolated in the way described above. The <img> element has a crossorigin attribute which allows developers to alter the outgoing request’s state. In this new mode, the following table describes the outgoing request’s properties in Fetch’s terms for various values:

Resource Request’s Mode Request’s Credentials Mode includeCredentials COEP:unsafe-none includeCredentials COEP:credentialless
<img src="https://same-origin/"> same-origin include true true
<img src="https://cross-origin/"> no-cors include true false
<img src="https://cross-origin/" crossorigin="anonymous"> no-cors omit false false
<img src="https://cross-origin/" crossorigin="use-credentials"> cors include true true

2.1.1. redirect

The decision to include credentials is done indepently for each request. The variable includeCredentials is set for the initial request, but also after each redirect.

For example, credentials are not included for a cross-origin no-cors request, but they can be added in the next request if it redirects to a same-origin resource.

2.2. Main resource requests

Cross-origin nested navigational requests (<iframe>, etc) are more complicated, as they present risks different in kind from subresources. Frames create a browsing context with an origin distinct from the parent, which has implications on the data it has access to via requests on the one hand and storage APIs on the other. Given this capability, it seems clear that we can’t just strip credentials from the nested navigational request and call it a day in the same way that we could with subresources.

For this reason, COEP:credentialless must be as strict as COEP:require-corp for navigational requests. It works identically.

That is to say:

  1. If the parent sets COEP:credentialless or COEP:require-corp, then the children must also use one of those headers. The two COEP values can be used and mixed in any order. If the children uses COEP:unsafe-none, its response is blocked.

  2. If the parent sets COEP:credentialless or COEP:require-corp, then the children is required to specify a CORP header when the response is cross-origin.

Note: To help developers with embedding cross-origin <iframe> without opt-in from the embeddee, the anonymous iframe project has been proposed. It is orthogonal to COEP:credentialless, which only affects subresources.

2.3. CacheStorage requests

See the issue: w3c/ServiceWorker/issues/1592

With CacheStorage’s put() and match() methods, a response fetched from a COEP:unsafe-none context can be retrieved from a COEP:credentialless or COEP:require-corp context.

Similarly to COEP:require-corp, the behavior of CacheStorage must be specified for COEP:credentialless.

The solution proposed is to store the includecredentials variable from the http-network-or-cache-fetch algorithm into the response. Then during the corp check, to require CORP for responses requested with credentials.

2.4. Cross-origin Isolation

Above, we asserted that the core goal of the existing opt-in requirement is to block interesting data that an attacker wouldn’t otherwise have access to from flowing into a process they control. Removing credentials from outgoing requests seems like quite a reasonable way to deal with this for the kinds of requests which may vary based on browser-mediated credentials (cookies, client certs, etc). In these cases, COEP:credentialless would seem to substantially mitigate the risk of personalized data flowing into an attacker’s process.

Some servers, however, don’t actually use browser-mediated credentials to control access to a resource. They may examine the network characteristics of a user’s request (originating IP address, relationship with the telco, etc) in order to determine whether and how to respond; or they might not even be accessible to attackers directly, instead requiring a user to be in a privileged network position. These resources would continue to leak data in a credentialless model.

Let’s assert for the moment that servers accessible only via a privileged network position can be dealt with entirely by putting a wall between "public" and "private", along the lines of the [private-network-access]. Successfully rolling out that kind of model would address the threat of this kind of leakage. As such [private-network-access] is a dependency of COEP:credentialless.

IP-based authentication models are, on the other hand, more difficult to address. Though the practice is unfortunate in itself (users should have control over their state vis a vis servers they interact with on the one hand, and sensitive data should assume a zero-trust network on the other), we know it’s used in the wild for things like telco billing pages. In a credentialless isolation model, resources these servers expose would continue to flow into cross-origin processes unless and until they explicitly opted-out of that inclusion via CORP. We can minimize the risk of these attacks by increasing CORB’s robustness on the one hand, and requiring opt-in for embedded usage on the other.

This leaves us with a trade-off to evaluate: COEP:credentialless seems substantially easier than COEP:require-corp to deploy, both as an opt-in in the short-term, and (critically) as default behavior in the long term. It does substantially reduce the status quo risk. At the same time, it doesn’t prevent a category of resources from flowing into attackers' processes. We have reasonable ideas about one chunk of these resources, and would simply not protect the other without explicit opt-in.

Perhaps that’s a trade-off worth taking? The mechanism seems worth defining regardless, even if we don’t end up considering it a fully cross-origin isolated context.


The rest of this document monkey-patches [HTML], [Fetch] in order to document the details of the bits and pieces discussed above.

3. Integration with HTML

Note: This corresponds to the following HTML specification change: whatwg/html/pull/6638.

3.1. Embedder policy value

In the embedder-policy-value section, add the credentialless value:

An embedder policy value controls the fetching of cross-origin resources without explicit permission from resource owners. There are three such values:

"unsafe-none"

This is the default value. When this value is used, cross-origin resources can be fetched without giving explicit permission through the CORS protocol or the 'Cross-Origin-Resource-Policy' header.

"require-corp"

When this value is used, fetching cross-origin resources requires the server’s explicit permission through the CORS protocol or the 'Cross-Origin-Resource-Policy' header.

"credentialless"

When this value is used, fetching cross-origin no-CORS resources omits credentials. In exchange, and explicit 'Cross-Origin-Resource-Policy' is not required. Other requests sent with credentials requires the server’s explicit permission through the CORS protocol or the 'Cross-Origin-Resource-Policy' header.

3.2. Parsing

In obtain-an-embedder-policy,

Step 4 about Cross-Origin-Embedder-Policy becomes:

4. If parsedItem is non-null and parsedItem[0] is "credentialless" or "require-corp":

  1. Set policy’s value to parsedItem[0].

  2. If parsedItem[1]["report-to"] exists, then set policy’s endpoint to parsedItem [1]["report-to"].

Step 6 about Cross-Origin-Embedder-Policy-Report-Only becomes:

6. If parsedItem is non-null and parsedItem[0] is "credentialless" or "require-corp":

  1. Set policy’s value to parsedItem[0].

  2. If parsedItem[1]["report-to"] exists, then set policy’s endpoint to parsedItem[1]["report-to"].

3.3. Compatible with cross-origin isolation algorithm

COEP:credentialess and COEP:require-corp differ in the Fetch specification. However, from the HTML specification point of view, they behave similarly. They are referenced together with the compatible with cross-origin isolation algorithm.

An embedder policy value is compatible with cross-origin isolation if it it either "credentialless" or "require-corp".

Then replace every occurrence of:

Old Replacement
coep’s value is "require-corp". coep’s value is compatible with cross-origin isolation.
coep’s value is "unsafe-none". coep’s value is not compatible with cross-origin isolation.

There are 10 occurrences to be replaced. In particular:

  1. COEP:credentialless can be used to enable cross-origin isolation, the same way COEP:require-corp does.

  2. If a document has a COEP policy compatible with cross-origin isolation, then the documents loaded in its <iframe> must also have a COEP policy compatible with , or be blocked.

4. Integration with Fetch

Note: This corresponds to the following Fetch specification change: whatwg/fetch/pull/1229

4.1. Omit credentials for no-cors cross-origin requests

Add the following algorithm:

To check Cross-Origin-Embedder-Policy allows credentials, given a request request, run theses steps:

  1. If request’s mode is not no-cors", return true.

  2. If request’s client is null, return true.

  3. If request’s client’s policy container’s embedder policy is not "credentialless", return true.

  4. If request’s origin is same origin with request’s current URL’s origin, return true.

  5. Return false.

Then, use it in the step 8.4. of the HTTP-network-or-cache fetch algorithm:

If Cross-Origin-Embedder-Policy allows credentials with request returns false, set includeCredentials to false.

4.2. The response’s request-include-credentials attribute

In the response section, add:

A response has an associated request-include-credentials (a boolean), which is initially true.

In the http-network-or-cache-fetch algorithm. Add step:

13. Set response’s request-include-credentials to includeCredentials.

Note: This attribute is used to require corp for opaque credentialled response retrieved via CacheStorage in COEP:credentialless context. See the cache-storage-request section.

4.3. Cross-Origin-Resource-Policy internal check

Modify the step 5 from the cross-origin-resource-policy-internal-check

5. If policy is null, switch on embedderPolicyValue:

"unsafe-none"
Do nothing.
"credentialless"
Set policy to "same-origin" if one of the following is true:
"require-corp"
Set policy to "same-origin".

5. Integration with ServiceWorker

There are no change to the ServiceWorker specification. The CacheStorage issue: w3c/ServiceWorker/issues/1592 is entirely resolved in this section by modifying the Fetch specification.

6. Security and privacy considerations

This allows embedding cross-origin resources with no explicit opt-in into a cross-origin isolated process. This process has access to powerful features like SharedArrayBuffer or precise timers. An attacker can exploit [Spectre] more easily. The attacker can potentially read the whole process memory and read those resources. This concern has been addressed in the cross-origin-isolation section.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[Fetch]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/

Informative References

[PRIVATE-NETWORK-ACCESS]
Titouan Rigoudy; Mike West. Private network access. URL: https://wicg.github.io/private-network-access/
[Spectre]
Paul Kocher; et al. Spectre Attacks: Exploiting Speculative Execution. URL: https://spectreattack.com/spectre.pdf