whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.11k stars 2.67k forks source link

Meta referrer being able to loosen Referrer-Policy header restrictions is a security vulnerability #5041

Open chris-morgan opened 5 years ago

chris-morgan commented 5 years ago

This was mentioned as part of a security bug report for a user content domain that is capable of serving arbitrary user files.

We serve various headers for security, such as a restrictive Content-Security-Policy, and this:

Referrer-Policy: never,no-referrer

The attack was an AppCache CHROMIUM-INTERCEPT one (c.f. #151), and part of the attack required exfiltration of secret URLs, which it did via the Referer header, using a meta redirect to a third party.

Our Referrer-Policy should have thwarted that. It didn’t, because apparently <meta name=referrer> can override it, so the user’s HTML included this:

<meta name="referrer" value="no-referrer-when-downgrade">

And so, the redirect being to another HTTPS site, the Referer header was included in full, rather than not at all as the Referrer-Policy had instructed.

What’s more, this seems to be behaving as specified.

https://html.spec.whatwg.org/multipage/urls-and-fetching.html#referrer-policy-attribute:

In general, the order in which these signals are processed are:

  1. First, the presence of a noreferrer link type;
  2. Then, the value of a referrer policy attribute;
  3. Then, the presence of any meta element with name attribute set to referrer.
  4. Finally, the Referrer-Policy HTTP header.

And https://w3c.github.io/webappsec-referrer-policy/#downgrade:

The spec does not forbid downgrading to less strict policies

As expanded on a little in that source, the trouble is that referrer policies do not lie along a single dimension.

Because of this, I suspect that fixing this would need to span two or three specifications, and be quite a substantial change. But I’m going to start by posting about it here, for discussion if nothing else, because I consider the present behaviour to be fundamentally broken, as demonstrated above.

I expect all policies (Content-Security-, Referrer-, &c.) to ratchet, and I believe that’s what everyone else expects too. But Referrer-Policy isn’t.

If policy values don’t lie along a single dimension, I expect user agents to track all of the policies that have been specified (e.g. an outer frame’s sandbox, a Referrer-Policy, a meta referrer, and a referrerpolicy attribute), and apply in each case whatever is the most restrictive, even though that equates to what is currently an unnameable referrer policy. (Perhaps even make that a feature, that a+b means whichever of a and b would be most restrictive in each case. I know that I’ve wanted the intersection of two referrer policies before, because they really are a weird mix.)

annevk commented 5 years ago

I recommend posting this as a feature request at https://github.com/w3c/webappsec-referrer-policy/issues/new as any change here needs buy-in from that community. The referrerpolicy attribute and various features in Fetch can also be used to override the policy to something less restrictive so this would basically be a new mechanism. Hope that helps.

domenic commented 5 years ago

In general, running untrusted user code on your own origin means you have already lost. Protecting against such scenarios is not within the threat model of the web. /cc @whatwg/security.

In such situations, you need to use a safelist-based HTML sanitizer if you expect any security. We won't design HTML or other web specifications around people who do not follow this requirement.

annevk commented 5 years ago

Given tools such as sandboxing, CSP, (proposed) Document Policies, and (proposed) Trusted Types, that's a rather strong statement, no? It certainly seems reasonable for the server to set a policy that constrains the page.

neilj commented 5 years ago

@domenic Actually, this is about untrusted user content being put on a deliberately different domain. Many companies use something like this – e.g. fastmailusercontent.com, googleusercontent.com, dropboxusercontent.com – it's on a separate domain because it's untrusted. However, you also want to isolate the untrusted content from each other on that domain, and also not leak back the address of the content at that domain if there's a link elsewhere (which is what this issue is all about).

mikewest commented 5 years ago

I think there's room for something that locks in a cap on the granularity of referrer information sent along with requests from a given context. Origin Policy seems like the right place to create such a thing, as it seems like it would only be useful if it could be applied to all pages that a given page's script might have access to. Filing a bug against referrer policy as @annevk suggested seems like the right way to go, as we'll want to integrate that spec with origin policy as @domenic fleshes out the latter.

Malvoz commented 3 years ago

@englehardt has a proposal for referrer trimming which I believe may intend to disallow sites from setting a more permissive referrer-policy than strict-origin-when-cross-origin.

domfarolino commented 2 years ago

I think there's room for something that locks in a cap on the granularity of referrer information sent along with requests from a given context.

My concern is that this'd give the impression that there's some enforced security characteristic when there really isn't. My understanding is that with CSP, you can guarantee your page will not be able to communicate with/exfiltrate data to other origins that you specify (maybe "guarantee" is a little strong, but that seems to be the intention? especially with things like navigate-to). This can be enforced via the header, which makes the page resilient to cross-site scripting attacks which cannot lift the restrictions applied by the header simply adding a loose <meta> tag. The same goes for permissions policy.

But for referrer policy, as long as you have 3p script running on your page you cannot stop it from sharing the full document's URL to any origin allowed by CSP. Even if this proposal makes it impossible to loosen the Referer header, from a security perspective that seems weak since you can just send the same info via a query param. So my fear is that this proposal would be interpreted by some as a strong security guarantee, like CSP, providing a false sense of security.

The original referrer policy mechanism doesn't provide this false sense of security because it is just setting the defaults, which is necessary for requests where you can't set a referrer policy manually, and useful if you don't want to apply referrerpolicy= attributes everywhere else. But if you want to make it impossible for script on your page to exfiltrate the document's URL somewhere, you probably have to use CSP to restrict what scripts are allowed on your page, or what origins you can send requests to.

annevk commented 2 years ago

I think there's a slight difference there that @johannhof made me aware of at some point, in that restricting the referrer forces the "attack" to become more visible and also reduces the number of channels you have to protect (i.e., reduced to just the URL). I think that is a compelling reason for referrer restrictions in general. I suppose I don't care too strongly about this particular issue, though I would favor following the general model of HTTP headers generally being authoritative.

johannhof commented 2 years ago

Yeah, I think from a privacy perspective having attackers migrate to increasingly less convenient (in the referrer case more prominent) channels is an expected side effect. However, that assumes continued effort on behalf of browsers to escalate protections to the next level which I don't think is given here (if this was fixed there would likely be no effort to mitigate this problem at URL level, at best accidentally through other privacy developments).