w3c / webappsec-permissions-policy

A mechanism to selectively enable and disable browser features and APIs
https://w3c.github.io/webappsec-permissions-policy/
Other
395 stars 154 forks source link

Support for declaring feature policy in HTML #55

Open clelland opened 7 years ago

clelland commented 7 years ago

In the most recent updates to the explainer and spec, there are two ways to set a policy on a document:

  1. Feature-Policy HTTP header
  2. allow* attributes on <iframe> elements

The HTTP header is the only way for a document to declare its own policy (the iframe attributes are, of course, set by the embedding document), and is the only way to override the policy on the top-level document.

Since not every web page author has the ability to control the headers sent with their documents, it would be good to have a way to set the declared policy in HTML.

Proposals

Support the <meta http-equiv> alternative to HTTP headers in HTML

We can treat <meta> elements as equivalent to HTTP headers, and allow document authors to include them in <head> elements. This has the advantage of being consistent with the Origin Trials mechanism, as well as with other http-equiv meta tags. We have to be careful in this case to not allow the tag to take effect after scripts have had a chance to run, though, as the policy enforced by the document should be effectively immutable, as far as scripts are concerned. Practically, I think this means we need to do one of two things:

  1. Don't allow the policy to have any effect if it appears after <script> or <link> elements, or if inserted via script. This might cause problems in browsers that can run scripts (like Chrome extensions) that aren't included in the <head>, since it may not be possible to include them early enough.

  2. Require that the policy be delivered within the first 1024 bytes of the response, so that user agents can scan for it before starting to parse the document, like <meta charset>. This isn't a scalable solution if other header-ish mechanisms want to adopt it as well; at some point, it's not going to be possible to cram everything into the first kilobyte.

Make the in-document declared feature policy an attribute on the <html> tag

This means that there can be only one such declared policy (which may be a good thing), and forces it to be declared on the very first element in the document. If very large, it might push a <meta charset> declaration out of the first kilobyte, but we might be able to define a shorthand format for such declarations. (If it doesn't look like it's trying to be an HTTP header, then maybe it doesn't need to have the same format)

Other ideas?

I'm certainly open to other ideas here.

zcorpan commented 7 years ago

(<meta charset> isn't the only way to specify encoding: UTF-8 BOM works as well as in-file encoding declaration, and of course charset parameter in Content-Type header works.)

clelland commented 7 years ago

That's true, but if you have full control over your headers, then it may be just as easy to include a Feature-Policy header as well.

annevk commented 6 years ago

I'd rather we not do this. This leads to all kinds of race conditions and you'll also get features you can only disable at the HTTP level. I'd rather not repeat the mess this created with CSP. Let's just encourage all hosting providers to give adequate header configuration options.

ojanvafai commented 6 years ago

@annevk if we do the mitigations mentioned in the post, I think that address the race conditions. Or, at least, that we should be able to come up with a set of limitations that do.

Practical reality is that hosting providers don't give adequate header configuration options. It's hard for me to imagine feature policy being the thing that pushes them to address that problem.

annevk commented 6 years ago

Hosting providers seem to have managed to provide them for CORS. CDNs have actually made significant strides just to get that to work. I'm not at all convinced we should add more complexity to the prescanner and such. Maybe if after all browsers ship this is the number one issue it becomes convincing, but I somewhat doubt this is going to be the problem.

yoavweiss commented 6 years ago

@annevk I saw very strong evidence that content providers are significantly more likely to adopt features in their http-equiv form over HTTP headers. I'm finding out if this data can be made public.

As far as adding complexity to the preloader, it will hardly be the first feature that adds state to it, and not the first one that adds state based on <meta> tags (e.g. viewport is taken into account in order to properly support responsive images).

eeeps commented 6 years ago

@yoav @annevk

Cloudinary supports Client Hints, which:

  1. can be enabled by authors with either an Accept-CH header in HTTP, or with a <meta http-equiv> in HTML.
  2. Chrome partially rolled back support for, pending an integration with Feature Policy.

We had a strong sense that customers preferred to use HTML, rather than HTTP headers, to enable CH. Data bears that out.

We looked at a sample of ~5,000 pages across ~1,000 domains whose subresource requests to Cloudinary included Client Hints.

So:

clelland commented 6 years ago

@eeps, what do you mean when you say

Usage within domains was almost entirely consistent.

Do you mean that within a domain, you're seeing identical CH declarations across all resources? Or just that domains always use either Headers or <meta> tags, but never both?

eeeps commented 6 years ago

@clelland Both. An initial survey of ~10K pages across a few hundred domains revealed only one page on one domain that did anything different than its siblings. (It used <meta http-equiv=Accept-CH content=DPR>, when 55 other pages on that domain used <meta http-equiv=Accept-CH content=DPR,Width,Viewport-Width>)

In light of this, and because the distribution of pages/domain drops off rather sharply (very few domains account for very many pages), I decided to look at %s of domains.

annevk commented 6 years ago

I still think it's hugely problematic, especially if this is to be part of the prescanner and such. We'd like to have a hard limit there of 1024 bytes to inspect and not increase that over time. But the more metadata you stuff into HTML, the less realistic that is going to be.

yoavweiss commented 6 years ago

@annevk I'm not familiar with the preloader implementation in Gecko, but why would you need such a limit, if you assume that HTML-based instructions are only applicable to resources that are discovered after them?

Under that assumption (which I think we can/should codify in spec), I don't think there's a particular need to buffer.

annevk commented 6 years ago

At that point you complicate the implementation as you have to deal with dynamic switching of policies. That seems particularly problematic for feature policy.

eeeps commented 6 years ago

@annevk because Feature Policy isn’t scoped to controlling the loading of external resources, but in principle, can alter all kinds of browser behavior?

If so, would it be awful to create a whitelist of feature policies that can be declared in HTML?

annevk commented 6 years ago

@eeeps that's what CSP does and it's rather terrible I think. I'd rather we keep things restricted to headers and figure out how to make it easier for developers to set them. A CDN could even support HTML markup and simply extract that to correct the headers before serving it up...

yoavweiss commented 6 years ago

For CDNs (and proxies in general), headers often come in before the HTML itself, so buffering, decompressing, and HTML parsing just in order to inject policies as a header would be a tough sale (and would result in significant user-visible latency).

I agree we could think of ways we could tackle the ecosystem issues that make it hard for developers to set headers. I think that's orthogonal to the fact that today it is hard for many of them. I suspect that shipping Feature-Policy without a markup way of setting it would significantly hurt its adoption. (and I think that applies to all policies, not only to the client hint ones)

@clelland - any comments on the implementation side of things? Would it make things significantly more complex to enable policies after the document was committed?

annevk commented 6 years ago

So FWIW, when we last discussed at Mozilla what we are planning on doing here, we were mostly interested in shipping the <iframe allow> part.

And it's not exactly orthogonal since as I pointed out before what you are proposing makes feature policy a dynamic thing rather than something you know about before you instantiate all the things.

clelland commented 6 years ago

@yoavweiss, I don't think that Chrome's implementation would be significantly complicated by this; we would have to enforce that it occurs early enough in the document stream though (in, or at least starting in, the 1024-byte prescanner area would be ideal, but possibly unrealistic). The problem in https://github.com/WICG/feature-policy/issues/55#issuecomment-411761640 is real -- you can't have a policy header occurring after something which it is supposed to control -- whether that's script functionality (or even script loading), or stylesheet parsing, or anything.

We do something similar with the Origin-Trial header -- it is specced that you can use a <meta> tag for it, but you have to do it in the <head> before any <link> or <script> tags are encountered. That might be sufficient here as well, but I haven't looked at it rigorously yet.

yoavweiss commented 6 years ago

it is specced that you can use a tag for it, but you have to do it in the before any or Githubissues.

  • Githubissues is a development platform for aggregating issues.