Skip to content

Latest commit

 

History

History
66 lines (38 loc) · 5.7 KB

README.md

File metadata and controls

66 lines (38 loc) · 5.7 KB

Resource Policy

@mikewest & @kinu, May 2020

A Problem

Servers have a good deal of control over whether or not they deliver a resource in response to a specific request. Fetch Metadata headers provide enough information to evaluate the risk of replying to a given request, and allow servers to implement reasonable heuristics around the way a request was made, and the context in which it will be used. These heuristics can be arbitrarily complex, and can be a powerful mitigation tool.

Once a resource is delivered, however, the server loses control. Consider a Service Worker which fetches a resource: servers can examine the incoming Sec-Fetch-* headers, and make a decision about whether or not to respond to that fetch(). Once the resource is cached, however, the server no longer has the ability to prevent the Service Worker laundering it into unexpected contexts. Likewise, servers have little control over the way that content delivered in containers like Web Bundles will be used.

In both these cases, the decision is binary: deliver the resource to be used in arbitrary ways, or don't. It would be nice to have more granular control on the client side.

A Proposal

Cross-Origin-Resource-Policy is a declarative version of a narrow slice of the server-side logic discussed above. Rather than evaluating the Sec-Fetch-Site header themselves, servers can instruct clients to discard a given response if it didn't come from an expected source. Perhaps we could extend servers' capability to make such declarations to include a broader swath of information available on the client-side.

For instance, servers may wish to ensure that a given resource is only loaded into certain contexts: it may be a document intended for framing, in which case it shouldn't be loadable as a script or image or etc. It may be a user-provided image, in which case it shouldn't be loaded as a plugin. Perhaps servers could declare a set of destinations, modes, or site relationships for which a resource is valid, and ask the client to reject it if used elsewhere?

Perhaps we could deprecate Cross-Origin-Resource-Policy in favor of a new response header (just Resource-Policy?) that has a more granular syntax. Something like the following might be a reasonable syntax to lock a resource to an embedded context:

Resource-Policy: dest=(iframe frame)

Or to ensure that a resource is only used as an image:

Resource-Policy: dest=image

The header would allow multiple restrictions, and enforce each of them. That is, to guarantee that a resource is used only by same-site endpoints as a script that was requested in CORS mode:

Resource-Policy: site=(same-site same-origin none), dest=script, mode=cors

Or (if w3c/webappsec-fetch-metadata#56 becomes a thing) to assert that a resource is only used by same-site endpoints as an iframe whose ancestors are also same-site:

Resource-Policy: site=(same-site same-origin none), frame-ancestors=same-site, dest=iframe

And so on, and so on...

These headers would be cached along with the response, and could be enforced by the client, even if the cached response was injected by a Service Worker, or extracted from a bundle.

FAQ

Couldn't we just extend Cross-Origin-Resource-Policy instead of minting a new header?

Yes. We could. Something like Cross-Origin-Resource-Policy: site=same-site, frame-ancestors=same-site, dest=iframe is certainly possible to ship, as CORP is defined as failing open. If folks could quickly align on a new syntax, there might still be room to change things up, but it would be somewhat unfortunate if a server that wished to impose more restrictions on a resource ended up instead imposing fewer unless they engaged in UA sniffing for browsers that didn't support the new hotness.

Shipping a new header avoids this problem, at the expense of adding complexity (and a deprecation story) to the platform. It might well be more reasonable to accept the backwards compatibility story above by reusing the existing header instead.

site=(same-site same-origin none) seems verbose.

Yes, it does. Perhaps we could come up with categorizations for these if we expect them to appear often. Or perhaps we could teach the client that same-origin implies (same-origin none) and same-site implies (same-site same-origin none).

Google's "Resource Isolation Policy" can't be expressed in this language.

Google suggests using a policy that rejects requests where Sec-Fetch-Site == 'cross-site' AND (Sec-Fetch-Mode != 'navigate'/'nested-navigate' OR method NOT IN [GET, HEAD]). This can't be expressed in this proposal for two reasons:

  1. It requires logic more complex than simple intersection.
  2. It checks against method (which, of course, we could easily add).

It might be worthwhile to add some complexity to the proposal to support this kind of check. It might also be worthwhile to encode some high-level set of canonical checks that we think are reasonable into explicit declarations. If the server says "This is a subresource.", then we could apply something like the resource isolation check. The server could likewise say "This is a top-level document." or "This is an embeddable document." with similar implications for the response. As more folks deploy Fetch Metadata-based rulesets, we'll hopefully improve our collective understanding of what these categories might look like...