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

Header should be sufficient in some cases to delegate features (esp. Client Hints) #408

Closed
clelland opened this issue Oct 9, 2020 · 11 comments

Comments

@clelland
Copy link
Collaborator

clelland commented Oct 9, 2020

I think that the changes made in #378 may have gone a bit further than necessary. #357, which was the motivation for the change, asked that blocking policies set in the header not be overridable with the allow attribute.

#378 does this, by making policy inheritance essentially the logical AND of parent-header and iframe attribute policy, and necessarily switches the header defaults for every feature to "*". (That was necessary so that developers would not be required to set the header in order to enable delegation at all, but could use just the attribute in the common case.) This also ends up making the allow attribute required in every case to delegate any permission.

Unfortunately, this model breaks some deployed use cases, where the header could previously have been used to explicitly grant permission to specific origins, and isn't very ergonomic for the Client-hint delegation case, where not only would every hint need to be specified on every frame, but we lose the ability to tell from the header which hints should be sent with subresource requests.

@yoavweiss suggested in email a small tweak which would reenable the use case of "enable delegation for specific sites with the header" and would allow Client Hints to be delegated with the header only. It involves treating an explicit header declaration, where a feature is mentioned in the header, with an associated allowlist, differently from the 'default' behaviour when the feature is not mentioned at all in a header.

Thinking about this a bit, it seems to me that the current state of the allow attribute when it comes to Client Hints and iframe delegation is not something that most developers would be able to use.

Currently developers are required to add an Accept-CH header in order to be able to delegate Client Hints (which already multiple folks found confusing). If we add a Permissions Policy requirement on top of that, that is not likely to make things better.

The way most people delegate permissions is by providing developers with a snippet of HTML they can integrate into their site, including a list of allow values. Asking them to muck around with headers is completely orthogonal to this flow, and doesn't serve much when it comes to the goal of CH being "accountable". The browser can keep track of an allow attribute in exactly the same way it can keep track of a header-based opt-in.

That that end, I propose:

  • To change Client Hints' delegation model so that an Accept-CH opt-in will not be required in order to be able to delegate hints to a header.
  • To change Permission Policy so that explicit restrictions are different than default restrictions
    • We want explicit restrictions to not be overridable, but implicit (by default) restrictions should be overridable.
    • That way, CH are handled correctly, without special-casing them.

I want to propose a change which would allow this, as well as the existing use cases, while still being web-compatible:

  • Header allowlist is 'default' unless otherwise specified. Iframe allowlist is 'default' unless otherwise specified.
  • Powerful features (currently "default 'self'") and high-entropy client hints:
    • Grant access to this document if header allowlist doesn't explicitly exclude 'self'
    • Grant access to same-origin frames if this document has access, and iframe allowlist doesn't explicitly exclude 'self'.
    • Grant access to cross-origin iframes if:
      1. This document has access,
      2. Either header or iframe allowlist explicitly includes its origin, and
      3. Neither header nor iframe allowlist explicitly excludes its origin.
  • Other features (syncxhr?) and low-entropy client hints ("default *"):
    • Grant access to this document if header allowlist doesn't explicitly exclude 'self'
    • Grant access to same-origin frames if this document has access, and iframe allowlist doesn't explicitly exclude 'self'.
    • Grant access to cross-origin iframes if:
      1. This document has access, and
      2. Neither header nor iframe allowlist explicitly excludes its origin.

We can do this with a simple change to the Define an inherited policy for feature in container at origin algorithm, inserting this step between what is currently steps 5 and 6:

If feature is present in policy’s declared policy, and the allowlist for feature in policy’s declared policy matches origin, then return "Enabled".

I have tested a Chromium CL with this, which passes all existing Feature-Policy tests, except for those which expose the new "Should be irrevocably blocked by the header" behaviour, but that is the behaviour that we want in any case, so those test expectations should be updated to match.

I'll work up a PR to add this, as well.

Opinions welcomed :)

@clelland
Copy link
Collaborator Author

clelland commented Oct 9, 2020

@annevk FYI, since this affects the header processing which has been a recent subject of some discussion.

clelland added a commit that referenced this issue Oct 9, 2020
This allows the header alone to enable delegation of a feature to specific
origins, if not otherwise blocked or affected by the container policy. The
order of precedence becomes:

1. Explicitly blocked by header: Disabled
2. Explicitly blocked by allow attribute: Disabled
3. Explicitly allowed by allow attribute: Enabled
4. Explicitly allowed by header: Enabled
5a. (Default behaviour when default allowlist is '*'): Enabled
5b. (Default behaviour when default allowlist is 'self'): Enabled if same-
    origin; Disabled if cross-origin.

Fixes: #408
@yoavweiss
Copy link
Contributor

@annevk
Copy link
Member

annevk commented Oct 12, 2020

I don't think Mozilla has taken a position on Client Hints and sync-xhr doesn't fit as a Permissions Policy as it's not disabled by default in cross-origin contexts. I thought we discussed before how that would be a better fit for Document Policy?

So I'm not really in favor of changing this in this way.

@clelland
Copy link
Collaborator Author

@annevk, I'm curious about where the objection stems from -- is is the algorithm itself, or the usage of Permissions Policy for CH in the first place?

For the algorithm -- the original Feature-Policy header, which Mozilla hasn't shipped, but which does see widespread usage (something like 1/150 page visits seen by Chrome), only really supported 'positive' declarations. The solution in #378 swings hard the other way, making negative declarations rock-solid, but breaking some existing uses. This idea keeps that guarantee from #378, but also doesn't break sites which were using the header to grant access.

This essentially just makes the inheritance algorithm use these priorities:

  1. Blocked by header: Disabled. (Strongest)
  2. Blocked by attribute: Disabled.
  3. Allowed by attribute: Enabled.
  4. Allowed by header (and not mentioned in attribute): Enabled
  5. Not mentioned in either: Do the default thing. (Weakest)

Agreed that sync-xhr fits better in Document Policy, it'll just take some time to get there. I'd be happy to rip it out of Permissions Policy, but it's not the only case of a default '*' allowlist. Client hints are a really interesting delegation case, where the attribute isn't as useful as the header for expressing intent, and it would be a shame to have to introduce a different delegation mechanism for it.

@annevk
Copy link
Member

annevk commented Oct 14, 2020

The objection is to making changes to Permissions Policy for the purposes of a feature that is pretty far from standardized.

@clelland
Copy link
Collaborator Author

clelland commented Nov 4, 2020

The objection is to making changes to Permissions Policy for the purposes of a feature that is pretty far from standardized.

The counter to that is that we are making changes anyway, from the behaviour in Feature-Policy to what is currently specced for Permissions-Policy. Nobody has shipped the new header yet, or even implemented as far as I know, so this is the time to make sure that we settle on the right behaviour.

I believe that this change is more web-compatible than the change from #378, while keeping the same security guarantees that were requested in #357. There are uses in the wild of the Feature-Policy header to grant access to a feature to an origin, where the allow attribute is then not required. This keeps that use case, while still making it possible to:
- Omit the header and use the default behaviour
- Use the header to irrevocably block access to any origin.
- Keep the rules the same for in-document decisions, such as client hints for subresources, as for subframe inheritance.

The delta between this proposal and #378 is just step 4 from above. It's still much easier to explain than the current FP algorithms, and means that Is feature enabled doesn't have to work differently than Define an inherited policy, which it currently does.

@annevk
Copy link
Member

annevk commented Nov 4, 2020

I'm not sure how this relates to web compatibility as this is a new header with new syntax. And client hints only has a single implementation too.

@clelland
Copy link
Collaborator Author

clelland commented Nov 4, 2020

It's two-fold, I guess:

  • We should support existing use cases (which isn't exactly the same as perfect compatibility with existing content, but makes it much easier for developers to transition from one header to the other, as it becomes just a syntax change in most cases)
  • The Feature-Policy header already shipped (in Chromium) with the existing semantics, and Chrome at least needs to support both headers for some time. Being able to switch Feature-Policy to use the same model as Permissions-Policy while not breaking existing sites is a web-compatibily issue for us.

@yoavweiss
Copy link
Contributor

Specifically RE Client Hints, the feature indeed has a single implementation at the moment, but it's unclear to me why that means that we need to make sure that infrastructure features like Permission Policy explicitly don't support its use-cases (or any future policy we'd like to apply to resource requests), especially when that comes with no drawbacks.

@annevk
Copy link
Member

annevk commented Nov 4, 2020

But we never had agreement on the use cases with the initial version. That covered all kinds of scenarios there was no agreement on.

@clelland
Copy link
Collaborator Author

clelland commented Nov 6, 2020

So, I still like this change -- it maintains more backwards compatibility with the shipped Feature-Policy header, it makes the Client Hints case more ergonomic, and I like the symmetry of the conditions:

Header Deny > Attribute Deny > Attribute Allow > Header Allow

That said, that's not really compelling enough to make the change, and there is definitely real value in being able to state that the allow attribute is always required for delegation to frames.

I'm going to close this; it may get re-visited if other compelling use cases come up, but for now, we can explore how best to make features work within the existing algorithms.

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

Successfully merging a pull request may close this issue.

3 participants