New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 733970 link

Starred by 5 users

Issue metadata

Status: WontFix
Owner:
Last visit > 30 days ago
Closed: Jul 3
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 2
Type: Bug



Sign in to add a comment

CSP blocks HTTP2 Server Push

Project Member Reported by lwe@google.com, Jun 16 2017

Issue description

Chrome 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.




 

Comment 1 by y...@yoav.ws, Jun 16 2017

What you are describing in (2) is not HTTP2 server push, but preload, which is subjected to CSP. OTOH, I don't think there's a current way to define nonces for preload instructions, nor that we should subject Link headers to CSP nonces.

Comment 2 by y...@yoav.ws, 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. 

Comment 3 by a...@google.com, 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. 

Comment 4 by xtof@google.com, 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.

Comment 5 by xtof@google.com, 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.

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

Comment 7 by mkwst@chromium.org, Jun 19 2017

Status: Available (was: Untriaged)
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.


Comment 8 by xtof@google.com, 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).
Project Member

Comment 9 by sheriffbot@chromium.org, Jul 12 2017

Labels: Hotlist-Google

Comment 10 by y...@yoav.ws, 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

Comment 11 by y...@yoav.ws, Oct 10 2017

Cc: andypaicu@chromium.org
 Issue 752922  has been merged into this issue.

Comment 12 by y...@yoav.ws, 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?
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
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.
Labels: Hotlist-EnamelAndFriendsFixIt
Labels: -Hotlist-EnamelAndFriendsFixIt

Comment 17 by y...@yoav.ws, May 5 2018

Owner: y...@yoav.ws
Status: Assigned (was: Available)
Status: WontFix (was: Assigned)
No longer reproducible, so closing. Reopened 752922 though as it seems like a separate issue.

Sign in to add a comment