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

Proposal: allow grouping permissions by year #481

Open
Seirdy opened this issue Aug 11, 2022 · 13 comments
Open

Proposal: allow grouping permissions by year #481

Seirdy opened this issue Aug 11, 2022 · 13 comments

Comments

@Seirdy
Copy link

Seirdy commented Aug 11, 2022

A comprehensive Permissions-Policy header to "opt out of everything":

accelerometer=(),ambient-light-sensor=(),attribution-reporting=(),autoplay=(),battery=(),bluetooth=(),browsing-topics=(),camera=(),ch-device-memory=(),ch-downlink=(),ch-dpr=(),ch-ect=(),ch-lang=(),ch-prefers-color-scheme=(),ch-rtt=(),ch-save-data=(),ch-ua=(),ch-ua-arch=(),ch-ua-bitness=(),ch-ua-full=(),ch-ua-full-version=(),ch-ua-full-version-list=(),ch-ua-mobile=(),ch-ua-model=(),ch-ua-platform=(),ch-ua-platform-version=(),ch-ua-reduced=(),ch-ua-wow64=(),ch-viewport-height=(),ch-viewport-width=(),ch-width=(),clipboard-read=(),clipboard-write=(),conversion-measurement=(),cross-origin-isolated=(),direct-sockets=(),display-capture=(),document-domain=(),encrypted-media=(),execution-while-not-rendered=(),execution-while-out-of-viewport=(),federated-credentials=(),focus-without-user-activation=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),hid=(),idle-detection=(),interest-cohort=(),join-ad-interest-group=(),keyboard-map=(),local-fonts=(),magnetometer=(),microphone=(),midi=(),navigation-override=(),otp-credentials=(),payment=(),picture-in-picture=(),publickey-credentials-get=(),run-ad-auction=(),screen-wake-lock=(),serial=(),shared-autofill=(),shared-storage=(),speaker-selection=(),storage-access-api=(),sync-script=(),sync-xhr=(),trust-token-redemption=(),unload=(),usb=(),vertical-scroll=(),wake-lock=(),web-share=(),window-placement=(),xr-spatial-tracking=()
  • Total size of the header value: 1384 bytes
  • Easy to read: no

Others have suggested an all permission; however, this isn't feasible because the meaning of all will change every time a new permission is added. Sites using all will not be forward-compatible.

My proposal: combine all these into a special permission called 2022. In 2023, new permissions might crop up; they won't be included in the 2022 permission. At the end of 2023, a new permission called 2023 can be created that will include 2022 and all permissions added in 2023.

The equivalent header content:

2022=()
  • Size of the header value: 7 bytes
  • Easy to read: yes
  • Estimated header-value size-savings: over 99%
  • Forward-compatible: yes
@marcoscaceres
Copy link
Member

I don't think this will work because what is supported per year will be user agent dependent (and unlikely to get agreement). It's also a bit of a footgun, because it doesn't actually tell you what is included per year.

@ecki
Copy link

ecki commented Sep 4, 2022

You can also use a generation or version number, but I also think it needs an easy way to „deny all“ for hardening headers.

@bershanskiy
Copy link
Member

bershanskiy commented Sep 4, 2022

For reference, this kind of issue is typically solved by using a library/middleware which automatically inserts headers. Basically, the developer just installs a library like Helmet for NodeJS Express or Talisman for Flask, and then the library can make educated guesses regarding the desired headers. These libraries/middlewares can provide an option to disable all permissions by default and permit only specified exceptions. For example, Flask supports both Permissions-Policy and its predecessor Feature-Policy at the same time. This approach would have the least compatibility fallout because then each project explicitly decides when to upgrade its middleware dependency and is actually in control of its own headers.

@Seirdy
Copy link
Author

Seirdy commented Sep 5, 2022 via email

@bershanskiy
Copy link
Member

This does not solve the issue of header bloat. Right now, the header is over 1kb and will only get larger with time.

Is header bloat that big of a problem in practice? I believe that if the HTTP header remains the same within the entire HTTP/2 or HTTP/3 session, then the header will be sent only once and saved by the server, and then reused afterward. This article gives an example for HTTP/2. HTTP/1.1 does not explicitly support header compression, but it does support compressing the entire message, so headers are somewhat compressed too.

@Seirdy
Copy link
Author

Seirdy commented Sep 6, 2022 via email

@annevk
Copy link
Member

annevk commented Sep 27, 2022

Well,

  1. We are designing standards for the long term, not for short term problems such as HTTP/1.1 still seeing usage.
  2. If this is about "bloat" and thus performance, presumably HTTP/3 adoption will do more for that.
  3. As such, I think we should be comparing wins relative to HTTP/3 with the latest in header compression.

@ecki
Copy link

ecki commented Sep 27, 2022

Another aspect, a deny-list approach is generally frowned upon in the security community. Why start it here. Yes the web might be of open nature, thats why a single header "lock everything i will request the stuff i need" sounds like a good compromise (even when it has the problem to define what "everything" means :)

@annevk
Copy link
Member

annevk commented Sep 27, 2022

Well, this is not a security feature. It's primarily a feature to delegate authority. It also allows imposing restrictions on oneself, but that is not the primary motivation. And safelisting would make it rather problematic to extend it going forward. E.g., it would make it hard-if-not-impossible to introduce a permission for <input type=file> as sites using safelisting might expect that to continue working.

@darobin
Copy link
Member

darobin commented Feb 21, 2023

One place where having a broad safelisting-based approach is when creating gateways to other systems such that their content is supposed be rendered at least to some degree but 1) it's potentially arbitrary and 2) you are comfortable occasionally breaking things that could be used for Bad Purposes™. I have the concern for (older-style, but that have to stick around) IPFS gateways. I could totally live with Permissions-Policy: anything-browsers-think-can-be-misused=().

@annevk
Copy link
Member

annevk commented Feb 22, 2023

The problem is that we don't know who will build upon it and wether or not they will hold it correctly.

@Seirdy
Copy link
Author

Seirdy commented Aug 4, 2023

I think we should be comparing wins relative to HTTP/3 with the latest in header compression.

@annevk I'm a browser "with the latest in header compression", fetching a web page. I race a TCP-based ALPN run against an HTTPS record lookup (Chromium's behavior). Either the HTTP/2 ALPN wins the race, or the HTTPS DNS record does not exist. Both are, and will remain, common scenarios. So I fetch the page over HTTP/2. This is the initial request; dynamic HPACK hasn't kicked in. I download a 1.56kb HTTP response header:

Permissions-Policy: accelerometer=(),ambient-light-sensor=(),attribution-reporting=(),autoplay=(),battery=(),bluetooth=(),browsing-topics=(),camera=(),ch-device-memory=(),ch-downlink=(),ch-dpr=(),ch-ect=(),ch-lang=(),ch-partitioned-cookies=(),ch-prefers-color-scheme=(),ch-prefers-reduced-motion=(),ch-rtt=(),ch-save-data=(),ch-ua=(),ch-ua-arch=(),ch-ua-bitness=(),ch-ua-full=(),ch-ua-full-version=(),ch-ua-full-version-list=(),ch-ua-mobile=(),ch-ua-model=(),ch-ua-platform=(),ch-ua-platform-version=(),ch-ua-reduced=(),ch-ua-wow64=(),ch-viewport-height=(),ch-viewport-width=(),ch-width=(),clipboard-read=(),clipboard-write=(),compute-pressure=(),conversion-measurement=(),cross-origin-isolated=(),direct-sockets=(),display-capture=(),document-domain=(),encrypted-media=(),execution-while-not-rendered=(),execution-while-out-of-viewport=(),focus-without-user-activation=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),hid=(),identity-credentials-get=(),idle-detection=(),interest-cohort=(),join-ad-interest-group=(),keyboard-map=(),local-fonts=(),magnetometer=(),microphone=(),midi=(),navigation-override=(),otp-credentials=(),payment=(),picture-in-picture=(),private-state-token-issuance=(),private-state-token-redemption=(),publickey-credentials-get=(),run-ad-auction=(),screen-wake-lock=(),serial=(),shared-autofill=(),smart-card=(),speaker-selection=(),storage-access=(),storage-access-api=(),sync-script=(),sync-xhr=(),trust-token-redemption=(),unload=(),usb=(),vertical-scroll=(),wake-lock=(),web-share=(),window-placement=(),xr-spatial-tracking=()

Now, through Alt-Svc or an HTTPS record lookup, I discover HTTP/3 support. I download a render-blocking asset over an upgraded HTTP/3 connection. This is the first HTTP/3 request; dynamic QPACK compression hasn't kicked in. I download a 1.56kb HTTP response header:

Permissions-Policy: accelerometer=(),ambient-light-sensor=(),attribution-reporting=(),autoplay=(),battery=(),bluetooth=(),browsing-topics=(),camera=(),ch-device-memory=(),ch-downlink=(),ch-dpr=(),ch-ect=(),ch-lang=(),ch-partitioned-cookies=(),ch-prefers-color-scheme=(),ch-prefers-reduced-motion=(),ch-rtt=(),ch-save-data=(),ch-ua=(),ch-ua-arch=(),ch-ua-bitness=(),ch-ua-full=(),ch-ua-full-version=(),ch-ua-full-version-list=(),ch-ua-mobile=(),ch-ua-model=(),ch-ua-platform=(),ch-ua-platform-version=(),ch-ua-reduced=(),ch-ua-wow64=(),ch-viewport-height=(),ch-viewport-width=(),ch-width=(),clipboard-read=(),clipboard-write=(),compute-pressure=(),conversion-measurement=(),cross-origin-isolated=(),direct-sockets=(),display-capture=(),document-domain=(),encrypted-media=(),execution-while-not-rendered=(),execution-while-out-of-viewport=(),focus-without-user-activation=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),hid=(),identity-credentials-get=(),idle-detection=(),interest-cohort=(),join-ad-interest-group=(),keyboard-map=(),local-fonts=(),magnetometer=(),microphone=(),midi=(),navigation-override=(),otp-credentials=(),payment=(),picture-in-picture=(),private-state-token-issuance=(),private-state-token-redemption=(),publickey-credentials-get=(),run-ad-auction=(),screen-wake-lock=(),serial=(),shared-autofill=(),smart-card=(),speaker-selection=(),storage-access=(),storage-access-api=(),sync-script=(),sync-xhr=(),trust-token-redemption=(),unload=(),usb=(),vertical-scroll=(),wake-lock=(),web-share=(),window-placement=(),xr-spatial-tracking=()

I've burned 3.2kb on what may be a small page, for one header. Rendering hasn't started yet. Add headers this is meant to complement (Document-Policy, CSP, etc.), all with an expanding list of directives, and header size becomes a problem. This is before we consider clients that lack HPACK/QPACK support (nearly all HTTP libraries I've used), or resources on other domains.

CSP had a good solution: grouping the fetch directives that existed at the time under default-src. Similarly, we can try defining a large set of permissions to group under one directive. Every few years, we could add a new meta-directive to keep forward- and backward-compatibility while also keeping header size from growing out of control.


POSSE note from https://seirdy.one/notes/2023/08/03/permissions-policy-header-bloat/

@Seirdy
Copy link
Author

Seirdy commented Nov 3, 2024

Just over a year later, a full invocation of the header that includes all Chromium permissions has grown from 1.56kb to 1.83kb:

Permissions-Policy: accelerometer=(),all-screens-capture=(),ambient-light-sensor=(),attribution-reporting=(),autoplay=(),bluetooth=(),browsing-topics=(),camera=(),captured-surface-control=(),ch-dpr=(),ch-device-memory=(),ch-downlink=(),ch-ect=(),ch-prefers-color-scheme=(),ch-prefers-reduced-motion=(),ch-prefers-reduced-transparency=(),ch-rtt=(),ch-save-data=(),ch-ua=(),ch-ua-arch=(),ch-ua-bitness=(),ch-ua-platform=(),ch-ua-model=(),ch-ua-mobile=(),ch-ua-form-factors=(),ch-ua-full-version=(),ch-ua-full-version-list=(),ch-ua-platform-version=(),ch-ua-wow64=(),ch-viewport-height=(),ch-viewport-width=(),ch-width=(),clipboard-read=(),clipboard-write=(),compute-pressure=(),controlled-frame=(),cross-origin-isolated=(),deferred-fetch=(),digital-credentials-get=(),direct-sockets=(),direct-sockets-private=(),display-capture=(),document-domain=(),encrypted-media=(),execution-while-out-of-viewport=(),execution-while-not-rendered=(),fenced-unpartitioned-storage-read=(),focus-without-user-activation=(),fullscreen=(),frobulate=(),gamepad=(),geolocation=(),gyroscope=(),hid=(),identity-credentials-get=(),idle-detection=(),interest-cohort=(),join-ad-interest-group=(),keyboard-map=(),local-fonts=(),magnetometer=(),media-playback-while-not-visible=(),microphone=(),midi=(),otp-credentials=(),payment=(),picture-in-picture=(),popins=(),private-aggregation=(),private-state-token-issuance=(),private-state-token-redemption=(),publickey-credentials-create=(),publickey-credentials-get=(),run-ad-auction=(),screen-wake-lock=(),serial=(),shared-autofill=(),shared-storage=(),shared-storage-select-url=(),smart-card=(),speaker-selection=(),storage-access=(),sub-apps=(),sync-xhr=(),unload=(),usb=(),usb-unrestricted=(),vertical-scroll=(),web-app-installation=(),web-printing=(),web-share=(),window-management=(),xr-spatial-tracking=()

My point about gradual growth of this header is evidenced by the the history of the Chromium DevTools generated protocol.ts file.

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

6 participants