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

Client Hint delegation to multiple subdomains #479

Closed
nicjansma opened this issue Jul 11, 2022 · 11 comments · Fixed by #516
Closed

Client Hint delegation to multiple subdomains #479

nicjansma opened this issue Jul 11, 2022 · 11 comments · Fixed by #516

Comments

@nicjansma
Copy link

Hi everyone!

As part of the User Agent Reduction initiative (in Chrome), we (Akamai mPulse RUM) are implementing some changes for our product to request the information that will soon be frozen/removed from the UA string via Client Hints instead. For example, we would like to continue being able to classify RUM visitors by their Platform Version (and not just Platform, which is included as a default CH header).

For our customers, the Akamai CDN (or their origins) will be injecting the necessary Accept-CH headers, e.g:

accept-ch: Sec-CH-UA-Platform-Version

Our product interacts with a few domains that we would like the Platform Version sent to, such as:

  • c.go-mpulse.net to fetch a configuration file
  • *.akstat.io to send the RUM beacon

So we were planning on including a Permissions-Policy header to delegate the requested Client Hints to those domains. For example, we were expecting to be able to send something like:

permissions-policy: ch-ua-platform-version=(self "https://*.akstat.io" "https://c.go-mpulse.net") 

This works fine for c.go-mpulse.net but our request of a wildcard in *.akstat.io does not work.

Our *.akstat.io domains receiving beacons have 100s+ subdomains mapping to specific paths we want the beacon to take, i.e. it may be abcd1234.akstat.io for one visitor and efgh5678.akstat.io for another. We don't know the domain at the time the HTML page is sent to the browser.

We were hoping that a wildcard (subdomain) match for *.akstat.io in the Permissions-Policy would work, but that does not seem to be the case (and isn't spec'd as such).

Without making any changes to the spec, we brainstormed a few options to resolve this:

  1. Delegate to all subdomains: ch-ua-platform-version=(self "*")
    • This is not ideal, as it sends whatever Client Hints we're requesting to other 3P domains that aren't requesting it
    • This will take additional bandwidth on all other 3P requests
    • For the sake of privacy, we would like to avoid doing this.
  2. Explicitly list all of the potential subdomains: ch-ua-platform-version=(self "https://abcd1234.akastat.io" "https://efgh5678.akastat.io" ...)
    • We have 100s of potential subdomains, so maintaining this list would be a challenge
    • It would waste a lot of bandwidth
  3. Use the JavaScript high-entropy API to get this data instead (in boomerang.js, the JS library that our customers use)
    • We are planning on doing this, but our customers are slow/hesitant to upgrade their boomerang.js versions so it may be years before they do so

Instead, we are hoping a proposal to allow for subdomains to match PP would be feasible and secure.

There was a bit of previous discussion on wildcards and subdomains here:

#129

And even a note from @clelland:

CSP allows much richer wildcards than feature policy currently does -- If FP adopted some of the same parsing logic, then you could cut it down to

But as far as I can tell, wildcards/subdomains didn't make it into the final Client Hints spec.

I understand that "star" wildcards (e.g. *.akstat.io) may have security concerns, but we were hoping some sort of syntax that might allow for any subdomain of an origin to get data, maybe something like this amateur attempt at a syntax:

permissions-policy: ch-ua-platform-version=(self "subdomains:https://akstat.io" "https://c.go-mpulse.net") 

Anyways, we're just trying to do the right thing and not request these hints and blast them all over!

Would love your thoughts,

@yoavweiss
Copy link
Contributor

@clelland @miketaylr - I'd love to hear your thoughts.

Could we use site as the delegation boundary here, on top of origins? (with some keyword that tells the browser that)

@mikewest
Copy link
Member

With CSP as a historical example, adding some sort of subdomain wildcard is probably reasonable. I'd like to understand why that doesn't exist in the current implementation, though: is there a good reason for the behavior we shipped, @clelland?

@clelland
Copy link
Collaborator

This was originally specced this way (with just origin / 'self' / *) because we felt it was the minimal amount of complexity needed to serve the known use cases. We didn't try to match CSP's general source-expression syntax, as it has much finer-grained wildcards than what made sense at the time for Feature Policy.

(The original Feature Policy proposal also had both positive and negative assertions, and trying to support arbitrary configurations like

   { "allow": "specific.general.example", "*.example"
     "disallow": "*.general.example", "*" }

was a lot more complexity than was warranted)

We could certainly add this now to the spec as a general mechanism. If we wanted parity with CSP, we'd end up supporting "*" for schemes, ports, and hosts (or subdomains). Anything below an origin level is irrelevant for Permissions Policy. (Site is difficult, since I think it necessarily involves interaction with the PSL or first-party-sets to scope a site correctly)

The compatibility story might be complicated if we did that, though -- without consistent cross-browser support, you might not be able to use such wildcards on all features. It would look like a non-fatal syntax error on browsers which didn't support it, so you'd have to fall back to using "*" or enumerating every origin anyway, if you needed that compatibility.

@yoavweiss
Copy link
Contributor

Oh, I somehow missed the fact that CSP's source lists can have wildcards. Matching that syntax would be ideal!

@miketaylr
Copy link
Member

* for subdomains does seem useful.

@yoavweiss
Copy link
Contributor

* for subdomains does seem useful.

Great! How do we make this happen?

@miketaylr
Copy link
Member

Let me see if someone on my team wants to tackle the spec PR + implementation work - does that sound OK @clelland?

@clelland
Copy link
Collaborator

Certainly, I'm happy to review PRs!

@arichiv
Copy link
Member

arichiv commented Jul 20, 2022

I'd be happy to send a PR and pursue this in Chrome for specifically the limited case:
$protocol://*.$eTLDplus1 e.g. https://*.foo.com. More than that and things become more dicey parsing wise without much gain (as far as I can tell) in terms of utility.

@arichiv
Copy link
Member

arichiv commented Jul 25, 2022

Early draft of a https://docs.google.com/document/d/1HtkQivbjO6TiP6uZdTt4KmTnWzbs5IZpEdrz59-fyYU/edit#

@arichiv
Copy link
Member

arichiv commented Mar 14, 2023

There is a new expansion of this proposal, specifically:

Subdomain wildcards in allowlists provided some valuable flexibility, but differed from existing wildcard parsers and required novel code and spec work. This intent will reduce that overhead by reusing parts of the existing Content Security Policy spec and permitting ‘scheme + wildcard domain’ and ‘wildcard port’ in the allowlist.

Specifically, this intent would adopt the definition of host-source and scheme-source instead of origin in the Allowlist definition while requiring that the path-part is empty (as Permissions Policies apply to matching origins). This would change three things from the prior wildcard implementation (all of which expand the range of allowed wildcards and none of which add new restrictions):

(1) Removing the eTLD+1 requirement for subdomain wildcards
Previously, you could not have a subdomain wildcard like “https://*.com” but could have one like “https://*.example.com”.
Now, you can have subdomain wildcards both like “https://*.com” and “https://*.example.com”.

(2) Allowing scheme restrictions on wildcard domains.
Previously, you could allow “*” but not restrict to a specific scheme like “https://*” or “https:”.
Now, you can still allow “*” but have the option of delegating to just a specific scheme like “https://*” or “https:” (the behavior of these is identical).

(3) Allowing port wildcards.
Previously you could delegate to the default https port like “https://example.com” or “https://example.com:443” (the behavior of these is identical), but there was no way to explicitly delegate to all ports like “https://example.com:\*”.
Now, you can still delegate to “https://example.com” or “https://example.com:443” but delegation is also permitted to a wildcard port like “https://example.com:\*”.

arichiv added a commit that referenced this issue Jun 1, 2023
This change harnesses [Content Security Policy matching](https://www.w3.org/TR/CSP3/#matching-urls)
to allow wildcards in the origins of Permissions Policy allowlists.
The goal of this is to provide greater granularity in permissions to
better balance the ease and risk of a wildcard permission against what
might otherwise be a long list of similar, yet distinct origins.

The only wildcard allowed before was *, which matched all origins.

Wildcards will now be supported for:
* https://example.com:\* (ports, any port for example.com over https)
* https://\*.com (hosts, any https origin ending in .com)
* https: (scheme-only, any https origin)

Feature: https://chromestatus.com/feature/5101218029895680

closes #479
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants
@mikewest @clelland @miketaylr @arichiv @yoavweiss @nicjansma and others