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

Denying self while still allowing subframes #480

Open
fergald opened this issue Jul 19, 2022 · 5 comments
Open

Denying self while still allowing subframes #480

fergald opened this issue Jul 19, 2022 · 5 comments

Comments

@fergald
Copy link
Contributor

fergald commented Jul 19, 2022

Should it be possible to prevent a frame/origin from using a feature while still retaining the ability to let other, specified origins use it?

This arose with the proposed unload feature (#444) but seems applicable to other features. There are 2 distinct uses

  • gradual removal of a "bad" feature, e.g. unload, sync-xhr`. It may not be possible to remove all uses of the feature from 3rd-party subframes or that may just take time but a site may have removed all uses themselves and do not want new uses to be accidentally introduced. Currently there is no way to enforce this with permissions policy, we are forced to grant all ancestor-frames access to the feature
  • reducing the attack surface for a "dangerous" feature. For example, limiting the use of some dangerous API to a different subdomain, e.g. example.com could place all uses of the payment feature in https://payment.example.com/ and deny use of that feature to https://www.example.com/. With this, compromising www.example.com does not provide access to this API and (hopefully) the JS on payment.example.com is smaller/simpler and harder to exploit.

Quote from @clelland in this thread on the history of this topic.

I believe that this was the biggest reason -- with the original model, it was trivial to work around not having access yourself. Even with a header like "Feature-Policy: some-feature 'none'", if we made it possible to delegate without having access yourself, then you could just create a frame to anywhere, even your own origin, with an allow attribute that would re-enable the feature. The way we closed that hole that was to be strict about not allowing delegation when you don't have access yourself.

Now that the allow attribute is no longer enough by itself, the loophole does not exist any more and so preventing usage but allowing delegation makes sense.

Syntax for discussion

For now, the syntax is not important but having a concrete proposal might be useful for discussing the idea.

One possible syntax would be to prepend ! to indicate that the origin in question cannot use the feature, so for example

Permissions-Policy: payment=(!"https://www.example.com/" "https://payment.example.com/")

or

Permissions-Policy: payment=(!self "https://payment.example.com/")
@clelland
Copy link
Collaborator

The WG talked about this at TPAC, and the consensus there was that this is probably a good idea, but that the name proposed might be confusing. (We wouldn't want people to assume that "!self" was the complement of "self"; that is, every origin except self)

I think that we need a single token to represent "don't include the origin this page was served from", to fit with the structured field definition. A general "prepend a ! before an otherwise-valid string" wouldn't parse.

I'll see about writing up the algorithm changes, while we bikeshed on the name (I'd propose painting the shed with "exclude-self", but I'm open to suggestions)

@annevk
Copy link
Member

annevk commented Sep 27, 2022

I think not-self or exclude-self is fine. I think the main problem is with ! which in CSS means something completely different. We also don't really lack the space (header bloat issues notwithstanding).

@tungnh28
Copy link

tungnh28 commented Nov 28, 2022

Even with a header like "Feature-Policy: some-feature 'none'", if we made it possible to delegate without having access yourself, then you could just create a frame to anywhere, even your own origin, with an allow attribute that would re-enable the feature. The way we closed that hole that was to be strict about not allowing delegation when you don't have access yourself.

I am thinking about a scenario explicitly for Chrome (might be exposed to other browsers too, I am not so sure), that is "partitioned" mode of permission delegation. We might have a slight conflict when permission access requires a function of both the 1P and embedding origins (such as storage-access permission feature or any future feature). All granted access of the feature from subframes will be removed, even the feature is still expected to be allowed in Permissions-Policy: feature=('exclude-self' "https://subframe.example.com/")

Imho exclude-self might be okay too, but ideally it would have to be "not-self-plus-delegate-nesting" or some such meaning, since the delegation seems to be an important factor here.

@fergald
Copy link
Contributor Author

fergald commented Nov 29, 2022

@tungnh28 I can't quite follow your meaning but if you are saying that permissions policy would not be able to grant a permission that would be removed by partitioning, then that seems reasonable. If it's some more involved than that, could you give a complete example?

@tungnh28
Copy link

you are saying that permissions policy would not be able to grant a permission that would be removed by partitioning.

That's what I meant, no further points than that.

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

No branches or pull requests

4 participants