CSP blocks HTTP2 Server Push |
|||||||
Issue descriptionChrome Version: 60.0.3112.24 (Official Build) beta (64-bit) OS: Linux What steps will reproduce the problem? (1) CSP with nonces + 'strict-dynamic' (2) Issue HTTP2 Server Push (e.g. link:<https://www.gstatic.com/foobar.js>; rel=preload; as=script;) What is the expected result? A server push should not be subject to CSP; rather CSP should be applied when the resource is actually referenced in the page (i.e. when the <script src=".." nonce=..> is evaluated_; the only difference is that if it's been pushed the content of that resource "is already there" in the browser. What happens instead? CSP blocks the pushed script.
,
Jun 16 2017
Mike - Do you have opinions on such CSP exemptions for Link header based preloads? Seems like those would be safe from traditional XSS perspective, but maybe there are other reasons they should be subjected to CSP.
,
Jun 16 2017
If it helps, I made a small repro case at: https://www.arturjanc.com/cgi-bin/link-csp-test.py I think preloads via the `Link` header probably shouldn't be subject to CSP, for two main reasons: 1) In cases where the attacker has an injection into response headers they generally already have the equivalent of an XSS, regardless of CSP (e.g. the attacker could inject two newlines and a subsequent CSP header would become part of the body and get ignored). 2) IIUC preloaded scripts aren't actually executed until they are sourced by the page. So if there is a CSP with a nonce and the attacker injects `Link: <https://evil.com/evil.js>` the script still wouldn't run unless the <script> element has a valid nonce.
,
Jun 16 2017
Re #1, "What you are describing in (2) is not HTTP2 server push, but preload, which is subjected to CSP". Technically that's true; however, server push and the Link: header are closely tied: https://w3c.github.io/preload/#server-push-http-2. In practice, web servers expose server push to applications via the Link: header (i.e. to instruct the sever to push a resource via HTTP2 server push, the application adds the appropriate link header to its HTTP responses). E.g., https://www.cloudflare.com/website-optimization/http2/serverpush/; https://blogs.akamai.com/2017/03/http2-server-push-the-what-how-and-why.html I.e., if an application uses server push, chrome will see those Link: response headers, and they then should not be blocked by CSP.
,
Jun 16 2017
It seems the real issue is that <link rel=preload> (and the Link: header equivalent) don't seem to honor the nonce attribute. This response: curl -i http://localhost:8000/cgi-bin/link.pl HTTP/1.0 200 Script output follows Server: SimpleHTTP/0.6 Python/2.7.6 Date: Fri, 16 Jun 2017 17:57:15 GMT Content-Security-Policy: script-src 'nonce-123' 'strict-dynamic'; object-src 'none'; report-uri /report Link: </foo.js>; rel=preload; as=script; nonce=123; Content-Type: text/html <!doctype html> <html> <head> <title>Link header 'strict-dynamic' test</title> <link href='/foo2.js' rel=preload as=script nonce=123> </head> <script src="/foo.js" nonce="123"></script> <script src="/foo2.js" nonce="123"></script> Results in 2 CSP errors for the Link: header and <link> tag: link.pl:1 Refused to load the script 'http://localhost:8000/foo.js' because it violates the following Content Security Policy directive: "script-src 'nonce-123' 'strict-dynamic'". 'strict-dynamic' is present, so host-based whitelisting is disabled. link.pl:5 Refused to load the script 'http://localhost:8000/foo2.js' because it violates the following Content Security Policy directive: "script-src 'nonce-123' 'strict-dynamic'". 'strict-dynamic' is present, so host-based whitelisting is disabled.
,
Jun 17 2017
I think there are a few separate threads in here.. A) client initiated preload requests (initiated due to <link> or Link header) *should* be subject to CSP. The actual policy is determined by provided `as` attribute, which is then mapped to a fetch destination [1]. This is to prevent opening up new vectors for exfiltrating data, etc. B) As long as client (UA) enabled server push during connection negotiation, the server can push arbitrary content to the client.. By definition, CSP does not apply at this stage. However, when the client requests a pushed resource, it'll first check relevant CSP policy. So push is *not* subject to CSP, but "pull" from the client is -- hope that makes sense. Connecting the dots.. A Link: rel=preload is a hint to the server that it's a candidate for push, and to the client it's a directive to "pull". So, if the server decides to push, it'll do so without any concern for CSP, but when the client initiates the pull.. CSP will apply. Hope that's coherent. :-) Also, FWIW, I think it reasonable for the UA to error out the push if it'll violate CSP.. why keep it in memory if we'll never use it? Current Chrome behavior may be unintentional, but it looks reasonable to me. [1] https://fetch.spec.whatwg.org/#concept-request-destination
,
Jun 19 2017
For Ilya's B: checking CSP after the server has already given us a resource doesn't make much sense. I'm fine with ignoring CSP checks in this case. For Ilya's A, I'd subdivide `<link>` and `Link`. For the former, I agree with his assessment: we have a document with a policy, and should run the request through that policy before loading. For the latter, I think I agree more with aaj@ that it doesn't make sense to apply the policy of the resource with which the `Link` header was delivered. I imagine we would want them to be subject to a theoretical policy known a priori (https://wicg.github.io/origin-policy/)), but for a policy delivered with the resource, we're trusting the server for the policy itself. Trusting the server for linked resources seems reasonable, and doesn't seem to open up significant new exfiltration surface. ---- Skimming through https://w3c.github.io/preload/, though, I'm not sure how to spec this. The document current punts out to https://html.spec.whatwg.org/multipage/semantics.html#concept-link-obtain, which pretty explicitly expects a `Document` to be available, which isn't the case for either `Link` or pushed resources. I'll file a bug to try to work that out.
,
Jun 21 2017
Can you comment on #5? It seems like if nonce worked in <link> and Link:, then we'd be all good: - if applications and web servers use Link: headers to signal candidates for server push, the app can then set proper nonce headers to ensure that the UA doesn't throw away the resource due to CSP when it sees the Link: header. - or, the application can use some other mechanism to signal push candidates to its web server (some other, non-standard header or whatever out-of-band signaling), in which case CSP doesn't apply (because there's no intertwined "pull" from the client).
,
Jul 12 2017
,
Sep 11 2017
So we have two separate issues here: 1) As stated in #5, `nonce` is not working on link elements or headers when it comes to preload. `nonce` is well specified for `<link>` [1] and skimming through the code, I'd (naively?) expect it to Just Work⢠for `<link>` element based preload, so this is probably a bug. I don't think we ever added `nonce` support to Link headers though. 2) As stated in #7, even if header based preloads don't have a nonce, we should provide them with a "CSP bypass route", as is they are content based XSS, they can override CSP anyway. mkwst@ - is that true also when CSP precedes those preload headers. I can see a scenario where an app is using user input in order to preload resources. Is there something such apps should do to protect themselves? (other than rigorously sanitize that input, or maybe inject those links as tags instead?) [1] https://html.spec.whatwg.org/#attr-link-nonce
,
Oct 10 2017
,
Oct 10 2017
It's fairly possible that 1) was fixed as part of https://bugs.chromium.org/p/chromium/issues/detail?id=702612 Can the OP verify if this is the case?
,
Oct 11 2017
We were running into this same issue when trying to use link rel="preload" and seeing the scripts blocked by CSP. Verified today that the issue seems fixed as of Canary 63.0.3236.0
,
Oct 11 2017
I can confirm that the issue described in 1) seems fixed. However, the issue marked as duplicate (see 752922), when the `<link>` element is generated dynamically from a nonced script, is still reproducible on Canary 63.0.3236.0.
,
Nov 10 2017
,
Feb 18 2018
,
May 5 2018
,
Jul 3
No longer reproducible, so closing. Reopened 752922 though as it seems like a separate issue. |
|||||||
►
Sign in to add a comment |
|||||||
Comment 1 by y...@yoav.ws
, Jun 16 2017