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

Support for declaring feature policy in HTML #55

Open
clelland opened this issue Feb 23, 2017 · 27 comments
Open

Support for declaring feature policy in HTML #55

clelland opened this issue Feb 23, 2017 · 27 comments
Labels

Comments

@clelland
Copy link
Collaborator

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
Copy link
Member

zcorpan commented Feb 23, 2017

(<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
Copy link
Collaborator Author

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
Copy link
Member

annevk commented Nov 24, 2017

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
Copy link
Collaborator

@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
Copy link
Member

annevk commented Dec 21, 2017

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
Copy link
Contributor

@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
Copy link
Contributor

eeeps commented Jul 20, 2018

@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.

  • Usage within domains was almost entirely consistent.
  • 98% of domains enabled Client Hints using a <meta http-equiv> tag in HTML.
  • 2% of domains enabled Client Hints using an Accept-CH header. Over half of these were operated by a single customer.
  • 3 domains used both <meta> and a header.

So:

  • Given a choice, customers strongly prefer enabling Client Hints in HTML, vs HTTP.
  • They will soon need to opt into sending us Client Hints using Feature Policy.
  • We want them to be able to use Feature Policy in HTML, too.

@clelland
Copy link
Collaborator Author

@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
Copy link
Contributor

eeeps commented Jul 20, 2018

@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
Copy link
Member

annevk commented Aug 9, 2018

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
Copy link
Contributor

@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
Copy link
Member

annevk commented Aug 9, 2018

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
Copy link
Contributor

eeeps commented Aug 9, 2018

@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
Copy link
Member

annevk commented Aug 10, 2018

@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
Copy link
Contributor

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
Copy link
Member

annevk commented Aug 10, 2018

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
Copy link
Collaborator Author

@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 #55 (comment) 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
Copy link
Contributor

it is specced that you can use a tag for it, but you have to do it in the before any or <script> tags are encountered.

That seems like a reasonable requirement to me.

@eeeps
Copy link
Contributor

eeeps commented Aug 10, 2018

it is specced that you can use a tag for it, but you have to do it in the <head> before any or <link> or <script> tags are encountered.

Once this tag is encountered, would it be possible to specify that future changes have no effect? So that, e.g., if a script removes <meta http-equiv="Feature-Policy" content="'self' https://video-player.cdn" /> from the <head>, calls to allowFullScreen() from scripts hosted on https://video-player.cdn will continue to work?

@Jamesernator
Copy link

but you have to do it in the <head> before any <link> or <script> tags are encountered.

This might cause undesirable delays on <link rel="preload" (and similar elements) that appear before it as they would need to wait till <head> is fully parsed before they can start.

An alternative might be to simply say that <meta http-equiv="Feature-Policy"> must be part of un-interrupted sequence of <meta> tags that start immediately within <head>

e.g. These would be allowed:

<head>
  <meta http-equiv="Feature-Policy" ...>
  <meta http-equiv="Content-Security-Policy" ...>
  ...
<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-Security-Policy" ...>
  <meta http-equiv="Feature-Policy" ...>
   ...

But this would not:

<head>
  <any-other-element ...>
  ...
  <meta http-equiv="Feature-Policy" ...>

@clelland
Copy link
Collaborator Author

@Jamesernator, I think we're in agreement -- allowing <link> before feature policy is completely specified causes problems, so at the very least, we would have to say that a policy declaration occuring after a <link> or <script> tag has no effect.

(Your proposal is stricter, but accomplishes the same thing, I think)

@mikewest
Copy link
Member

Coming in late, as @yoavweiss added this to the TPAC agenda:

In hindsight, I am not enthusiastic about CSP's <meta> mechanisms. I do believe that they create adoption opportunities that wouldn't otherwise exist, but I think @annevk's intuitions around the badness of runtime changes to a page's policy are real. In particular, I'd note two things:

  1. CSP is one of the things that's going to be tough for Chromium to extract from the (untrusted) renderer process and move into a (trusted) browser process. We're required to provide a channel from the renderer to the browser for additions to the policy, which is pretty unfortunate architecturally.

  2. The bits of CSP that are accessible from <meta> are (still, I think) entirely negative in action, as injection attacks cause us to treat the embedded HTML with a little more caution than HTTP response headers (again in hindsight, we should have required TLS for CSP). In a world where some features are disabled by default, we'd need to create the same list of safely-embeddable Feature Policy directives. I'm not sure that's a great use of our time.

Looking forward to some conversation tomorrow!

@emersion
Copy link

emersion commented Dec 1, 2021

This feature would be pretty useful, because it allows web applications to ship with a baseline policy, without requiring all users to configure their web server to manually add the policy and keep it up-to-date. For instance, I maintain a chat webapp, and I ship a restrictive Content-Security-Policy in a <meta> tag. All of the deployments of my webapp will use the policy without any action needed from my users.

@npdoty
Copy link

npdoty commented Apr 18, 2022

It would help address some open questions about site owners who want to opt in or opt out of certain advertising-related mechanisms if Permissions-Policy and other policy statements could be made as http-equiv meta tags.
patcg-individual-drafts/topics#60

I don't have a position/insight into the first 1024 bytes question, but it does seem like the policy should be static for a page and these tags would need to come before any script tags in order to be effective.

@annevk
Copy link
Member

annevk commented Apr 22, 2022

That still gives you mutable policies. As the policies can then change after you've seen all HTTP headers. That's a problem as there's a number of decisions you want to make at that point.

In theory and with vast amount of effort that I don't think anyone is willing to do, you could delay further until you've scanned x bytes, but that would also end up delaying other things. Overall that doesn't seem like an attractive or likely successful path to go down.

The real solution here is empowering developers so they get to set their own HTTP headers. That would solve this problem and countless others and it would solve them now, rather than whenever browsers get around to adding support for something that doesn't even work very well.

@npdoty
Copy link

npdoty commented Apr 22, 2022

Do we have a feasible plan for getting universal (or near-universal) access to set HTTP headers by web developers? (Genuine question! I don't actually know what's blocking developers at the moment or what software would need to add this functionality.)

I agree that that would be preferable, but if it won't actually happen, then browser-based alternatives still seem more feasible even if they are annoying for browser vendors to implement.

@dmarti
Copy link

dmarti commented Apr 22, 2022

@npdoty No, not universally. It is up to the hosting platform. A basic shared host that gives you old-school CGI or .htaccess makes it easy to set headers. GitHub Pages -- which is a great, popular service in most ways -- does not let you set headers.

Some advertising-related proposals are using Permissions-Policy to set policies for tasks related to content parsing, such as "is an ML system allowed to train on the content of this page". In order to be a good fit for this, the party that has control of content -- such as the operator of a blog or online store -- is going to need to be able to set the policy. (see patcg-individual-drafts/topics#60)

The web user who is best able to set the Permissions-Policy for the ad-related proposals is the person who is in control of the content of the page, whether or not they fit a particular definition of "developer."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

13 participants