Skip to content
This repository has been archived by the owner on May 5, 2022. It is now read-only.

Interaction of 103 and CSP #114

Closed
annevk opened this issue Dec 15, 2017 · 26 comments · Fixed by whatwg/html#7675
Closed

Interaction of 103 and CSP #114

annevk opened this issue Dec 15, 2017 · 26 comments · Fixed by whatwg/html#7675

Comments

@annevk
Copy link
Member

annevk commented Dec 15, 2017

At the point of a 103 there's no CSP policy yet. How does fetch even get invoked for those?

@yoavweiss
Copy link
Contributor

I don't think this is the right repo to open issues against Early Hints. You may want to try https://github.com/httpwg/http-extensions

@annevk
Copy link
Member Author

annevk commented Aug 20, 2018

Sigh, how sure are you that this is not going to be a game of ping-pong?

@yoavweiss
Copy link
Contributor

@mnot @kazuho - do you agree that the above issue belongs at the HTTPWG?

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

As I expected this is found to be an issue with rel=preload, not Early Hints (see httpwg/http-extensions#687 (comment)).

@yoavweiss yoavweiss reopened this Aug 22, 2018
@kazuho
Copy link

kazuho commented Aug 22, 2018

FWIW, my view is that CSP does not "restrict" how resources designated by preload links are being fetched, and therefore that clients do not need to worry about what the final value of the CSP header field will be when evaluating the preload links in a 103 response.

Consider the following example.

HTTP/1.1 200 OK
Content-Security-Policy: img-src https://example.com/; script-src 'none'

...
<script src="/script.js"></script>

The client will not fetch /script.js, because it is not allowed by the CSP header field.

Consider the next example.

HTTP/1.1 200 OK
Content-Security-Policy: img-src https://example.com/; script-src 'none'
Link: </script.js>; rel=preload; as=image

...
<script src="/script.js"></script>

/script.js is fetched, even though CSP says do not.

CSP defines what to fetch based on how it is used. Preload links are a way to let the client start fetching resources before it sees how it is actually being used.

To put it another way, it is already the server's responsibility to sanitize the preload links that it sends. Adding support for preloads links in 103 does not change the fact.

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

Meh, as I said elsewhere, what if the Content-Security-Policy was instead default-src 'self'?

@kazuho
Copy link

kazuho commented Aug 22, 2018

You can do whatever you want.

I am merely pointing out that checking the value of "as" attribute of a preload link against the value of CSP is not a security feature (because the value of "as" can be faked). And that therefore clients do not need to wait for the final value of CSP to determine how to handle preload links in 103.

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

@kazuho that's simply not true for the policy I defined.

@kazuho
Copy link

kazuho commented Aug 22, 2018

@annevk If that is the case, do you think that the client is allowed to fetch /script.js when it sees the header fields of the following response (but before it sees the script tag)?

HTTP/1.1 200 OK
Content-Security-Policy: img-src https://example.com/; script-src 'none'
Link: </script.js>; rel=preload; as=image

...
<script src="/script.js"></script> <!-- this is the only place where /script.js is used -->

PS. My view is that the preload specification allows the client to start fetching /script.js when it sees the link header field, because the designated type (image) is not forbidden by the CSP header field. As I said before, this is an example showing that "preloads" initiated by link header fields are not governed by CSP (which defines what to load based on how it is being used).

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

Sure, if your CSP policy is weak with respect to outgoing requests, outgoing requests can be made.

@kazuho
Copy link

kazuho commented Aug 22, 2018

Right. And that is even the case for default-src being none. For example, https://cdn.example.com/script.js will be fetched in the following example.

GET / HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Content-Security-Policy: img-src https://cdn.example.com/; default-src 'none'
Link: <https://cdn.example.com/script.js>; rel=preload; as=image

...
<script src="https://cdn.example.com/script.js"><!-- this is the only place where /script.js is used -->

So if you want to forbid preload links initiating fetches that might violate CSP, you need to ignore all preload links if the URL of the link is forbidden by any destination type. For example, if object-src is set to none, a client will be required ignore all preload links regardless of their types.

I do not think that we would want make such a change the preload's spec, because that would make it very hard to use preload and CSP at the same time.

Therefore, I suggest to continue considering that the preload links as not being policed by CSP, which in turn removes the concern of preload links found in 103 potentially violating CSP.

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

It will only be fetched because you left a gaping hole in your policy?

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

(Though if you trust cdn.example.com it doesn't seem problematic that requests go there.)

@kazuho
Copy link

kazuho commented Aug 22, 2018

It will only be fetched because you left a gaping hole in your policy?

By referring to "gaping hole", are you suggesting that properties like img-src should point to directories that only contain certain kind of resources (e.g. img-src should only contain images)?

I would argue that that is not always expected. For example, it would be natural to expect "self" to contain more than one types of resources.

(Though if you trust cdn.example.com it doesn't seem problematic that requests go there.)

I agree. Maybe we can also agree that loading resources designated by preload links that belong to "self" can be fetched without consulting the final value of CSP?

@annevk
Copy link
Member Author

annevk commented Aug 22, 2018

I mean that if you don't want outgoing requests to cdn.example.com, you shouldn't include it in your policy. If you're fine with outgoing requests there, you can include it, and there'll be ways to make requests there. I don't really think the as feature is of relevance here though.

I'm not sure what you mean by your "self" example. Do you mean same-origin fetches? What if the policy were default-src 'none' and nothing else?

@kazuho
Copy link

kazuho commented Aug 23, 2018

I mean that if you don't want outgoing requests to cdn.example.com, you shouldn't include it in your policy. If you're fine with outgoing requests there, you can include it, and there'll be ways to make requests there. I don't really think the as feature is of relevance here though.

Are you suggesting that a link preload header with whatever as value will initiate a fetch if any of the CSP restrictions match the URL of the specified resource? That for example, the client is allowed to initiate a GET request for /script.js when it sees the following response?

content-security-policy: default-src none; img-src self
link: </script.js>; rel=preload; as=image

I might agree that such model does not contradict with what is defined by the preload specification. However, it is different from what CSP defines. To paraphrase, I would argue that such model either special-cases preload or puts preload outside of CSP.

Considering that, the question is why we would want to apply such set of rules to preload. What would be the reason to apply CSP rules to link preload headers in a different way than how they apply to the requests generated by the document?

IIUC, CSP is based on the assumption that HTTP headers are harder to tamper than the document itself. That's why CSP as a header is used to control what requests the browser generates (while it processes the document).

IMO, it would be natural to argue that CSP and preload link headers can be trusted to same extent, because they are both headers. If so, why do we need to police the values of a preload header using CSP?

@annevk
Copy link
Member Author

annevk commented Aug 23, 2018

CSP is a fetching policy for the resource (and as I indicated before, soon the entire origin) and as such controls all fetches. If your policy is default-src none no fetches are to be allowed. Headers might well be set by different parties and it should be enough to just control CSP and not also have to be aware about all other possible headers that might be set.

@kazuho
Copy link

kazuho commented Aug 23, 2018

Headers might well be set by different parties and it should be enough to just control CSP and not also have to be aware about all other possible headers that might be set.

I am not sure if that is a viable security model. Just having CSP protected while letting other parties set arbitrary headers does not work. Consider alt-svc, location and status (in CGI), HSTS...

The server can only send the headers that it considers valid. I do not see why preload links should be an exception here.

@annevk
Copy link
Member Author

annevk commented Aug 23, 2018

I think it would be very confusing if <link> was guarded by CSP, but Link was not. That doesn't seem acceptable. I agree that you need to control security-sensitive headers, but giving away control over Link should be reasonable without having to reimplement CSP on the server.

@kazuho
Copy link

kazuho commented Aug 23, 2018

I think it would be very confusing if <link> was guarded by CSP, but Link was not.

That might be true, but I would argue that the way you propose to apply CSP to preload links is already very complex.

A fetch initiated by an ordinary tag is allowed by CSP if (type-of-tag, resource-URL) is whitelisted. For example, <script> loads a script if the designated URL is permitted by the script-src directive (or default-src when scirpt-src is omitted).

Whereas in case of preload links, it is impossible to determine how it would be used in a trustable way. This is because the tag type (i.e. link) does not indicate how the resource would be used, and because "as" attribute is controlled by the party that generates the preload links. IIUC, the rule you proposed in
#114 (comment) is to allow the preload link to initiate a fetch when any directive of the CSP ruleset allow fetching from that URL.

Isn't that confusing?

If you are interested in having a simple ruleset, I might suggest ignoring all preload link tags when CSP is being used. Then, every fetch will have the correct type being associated (i.e. we know that a resource fetched by <script> is used as a script). At the same time, we could allow preload link headers to designate resources without consultation to CSP.

@annevk
Copy link
Member Author

annevk commented Aug 23, 2018

It's not complex. Fetches are governed by the Fetch standard, which dispatches to CSP, which either allows or blocks the fetch. You are making it complex by ignoring that CSP applies to all outgoing fetches and instead focusing on type system, which doesn't matter much for governing outgoing requests. At this point it's starting to feel disingenuous.

@kazuho
Copy link

kazuho commented Aug 23, 2018

Fetches are governed by the Fetch standard, which dispatches to CSP, which either allows or blocks the fetch. You are making it complex by ignoring that CSP applies to all outgoing fetches and instead focusing on type system, which doesn't matter much for governing outgoing requests. At this point it's starting to feel disingenuous.

I agree with your observation but disagree with your view that it is not complex.

CSP, as a mechanism to control how the resources are applied, need to be a type-specific whitelisting. It can be naturally applied to fetches being initiated by ordinary tags (e.g. <script>), because the tag tells the client how the resource being fetched will be used.

OTOH, as you have pointed out, fetch does not need to be controlled in a type-specific way, and fetch initiated by a link preload cannot be controlled in such a way because it does not provide a trustable way of determining how the fetched resource will be used. A type-agnostic whitelist is what we need here, and as you have suggested, creating a union of URLs listed in a type-specific whitelist is one way to do it.

What I am arguing is that this application of type-specific whitelist to type-agnostic preload mechanism is complex and also the source of confusion.

It might not been a big issue with final responses. But the impedance mismatch is becoming greater with the introduction of 103. Therefore, I am suggesting that it might be worthwhile to consider alternative models (for example, see the last paragraph in
#114 (comment)) rather than trying to add a special rule on how to handle preload links 103 in relation to CSP.

@annevk
Copy link
Member Author

annevk commented Aug 23, 2018

The preload mechanism is not type-agnostic, as was specifically added to work with the CSP types... (Well, fetch destinations.) And note that Link: <./script> rel=preload; as=image will "bypass" img-src self; default-src none, but cannot then be executed with <script src=./script>.

And indeed, the problem here is 103, I don't think any browser is willing to bypass CSP for non-103 Link. Did you test that and found it doesn't work?

@yoavweiss
Copy link
Contributor

TBH, I'm not sure what action is required on behalf of the spec editors here. I think this is a discussion worth having, but still think it's a discussion that needs to happen at the HTTPWG.

So, I'm keeping this issue open for now, but marking it as "non-blocking". We can reconsider if/when user-agents will consider actually implementing Early Hints.

@annevk
Copy link
Member Author

annevk commented Oct 16, 2018

I'd appreciate if you brought that up with httpwg/http-extensions#687 and convinced them.

@noamr
Copy link
Contributor

noamr commented Mar 28, 2022

This is fixed in whatwg/html#7675

domenic pushed a commit to whatwg/html that referenced this issue Apr 14, 2022
mfreed7 pushed a commit to mfreed7/html that referenced this issue Jun 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants