8000 Consider preserving destination on `new Request(request)` · Issue #717 · whatwg/fetch · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Consider preserving destination on new Request(request) #717

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

Closed
wanderview opened this issue Apr 25, 2018 · 18 comments
Closed

Consider preserving destination on new Request(request) #717

wanderview opened this issue Apr 25, 2018 · 18 comments

Comments

@wanderview
Copy link
Member

Consider the situation described in this blog post:

https://qubyte.codes/blog/content-security-policy-and-service-workers

Essentially a site has set a CSP policy of default-src self; img-src * on all its served resources. The intent is to restrict cross-origin resource loads to only images.

This works on a normal page, but does not work when the CSP is applied to the service worker script. The service worker script does fetch(evt.request) which triggers a network request with an empty string destination. This in turn causes the CSP check to fall back to default-src and fail.

I think we should consider preserving the destination when an existing Request is passed as the constructor input. We would only clear the destination if any of the init params are passed to alter the Request. So basically another thing to sanitize under step 14 in:

https://fetch.spec.whatwg.org/#dom-request

This would allow the service worker to have a CSP policy like default-src self; img-src * and perform pass through fetch requests for images. It effectively expresses that the service worker is allowed to perform cross-origin network requests on behalf of the browser only for images. Only the browser can mint destination "image" requests.

The risks of doing this seem to be:

  1. The service worker could consume the cross-origin image request in a different way than passing it to respondWith(). If its able to force some other kind of data through an img element src URL, then maybe it could access non-image data.
  2. The service worker could put the "image" destination Request in Cache API and pull it out to use later.

I'm not sure how bad these risks are. It just seems unfortunate that we effectively require service workers with pass-through fetch handlers like this to disable their CSP protections in the service worker. Effectively the site has to let their service worker fetch() any cross-origin resources if it wants to support pass-through fetch of a specific thing like cross-origin images.

@annevk
Copy link
Member
annevk commented Apr 26, 2018

1 is essentially why we don't do this. See also #521. This functionality would allow an advanced XSS attack to bypass CSP and serve the response of an image (which might have "unsafe domains" safelisted) as a script.

@annevk
Copy link
Member
annevk commented Apr 26, 2018

The only way to make this work is if we guard the response (make it opaque (though maybe slightly less than opaque is okay) + special destination marker) so it can only be used for its intended purpose and cannot be read from otherwise.

@yoavweiss
Copy link
Collaborator
yoavweiss commented Apr 26, 2018
edited
Loading

I find it surprising that currently we just nullify the destination in such cases, since it is problematic for CSP, as @wanderview stated.
From a request priority perspective, it is maintained in such pass through scenarios, right?

In any case, would be great to be able to maintain the destination, at the price of opaque responses. (maybe an opt-in is required, for cases where people want to manipulate the response and don't care about the destination?)

@annevk
Copy link
Member
annevk commented Apr 26, 2018

It's problematic for CSP if you don't nullify it, as I've explained many times on many threads... If you pass the Request object directly to event.respondWith() it's unchanged, since you don't get the response in that case.

@yoavweiss
Copy link
Collaborator
yoavweiss commented Apr 26, 2018

It's problematic for CSP if you don't nullify it, as I've explained many times on many threads...

I understand. At the same time you stated above that:

The only way to make this work is if we guard the response (make it opaque (though maybe slightly less than opaque is okay) + special destination marker) so it can only be used for its intended purpose and cannot be read from otherwise.

Which seemed like a way forward

If you pass the Request object directly to event.respondWith() it's unchanged, since you don't get the response in that case.

If there's already a way to get around the destination nullification then that's great. Can you point me at an example?

@annevk
Copy link
Member
annevk commented Apr 26, 2018

Sorry, I was mistaken, the only way is to not invoke respondWith() and have a genuine "pass-through" (for some reason I thought respondWith() also took a Request).

A guarded opaque response has always been presented as a way forward, but nobody has been willing to put in the work.

@yoavweiss
Copy link
Collaborator

the only way is to not invoke respondWith() and have a genuine "pass-through"

Does that also work conditionally? e.g. have the fetch event handler respondWith() on some requests, but pass-through e.g. "image" destination requests in the above scenario?

@annevk
Copy link
Member
annevk commented Apr 26, 2018

@yoavweiss I think this should work, but I haven't tested:

onfetch = e => {
  if (e.request.destination !== "image") {
    // Do things here.
  }
}

@yoavweiss
Copy link
Collaborator

Yeah, if that works, that could be a way forward for people to tackle this use-case.

@qubyte
Copy link
qubyte commented Apr 26, 2018

I think this went off track a little... The confusion was not that images shouldn't be handled by the service worker (they should in my use case), it was that the service worker is subject to connect-src for all requests it does manage.

It may well be the correct way for the fetch to behave, but it was a struggle for me (I failed until helped by Jake) to find any mention of it in the fetch spec/documentation.

@annevk
Copy link
Member
annevk commented Apr 26, 2018

@qubyte basically once you use fetch() you're bound by connect-src since fetch() is quite powerful.

There's an open question here if you would be okay with opting into getting a response you can store in the Cache API and such, but otherwise only use for <img> and not be able to inspect much from. If that would work, we could make img-src work for fetch() when you opted in that model. It's a little bit unclear to me though if it's worth all the trouble.

@qubyte
Copy link
qubyte commented Apr 26, 2018

Yup, I understand this now, and it makes sense (at least as a default). My concern is the mixture of it not being so obvious and the difficulty in discovering why (thus my post).

@jakearchibald
Copy link
Collaborator

My gut feeling is that requiring connect-src is simpler than creating a new kind of opaque response.

@yoavweiss
Copy link
Collaborator

Requiring connect-src is not always feasible - consider the case of an optimization service installing SW on content it does not control. It can theoretically add connect-src directives which are the sum of all other directives, but it can be tricky, and somewhat weakens CSP's protection guarantees.

@wanderview
Copy link
Member Author

Its unfortunate, though, if I have to allow my service worker script to hit any cross-origin resource when I know my site only makes cross-origin requests for a particular destination type. It basically means you can't use CSP to lock down your SW script if you have any cross-origin resources you need to handle with respondWith().

@wanderview
Copy link
Member Author
wanderview commented Apr 26, 2018

Maybe a stupid idea, but could we:

  1. Stash the original request's destination in some internal value. Lets call it "original destination".
  2. Add a CSP token that allows connect-src to inspect the original destination and apply its policy instead. Lets call this "use-original-destination" for lack of a better name for now.

This would let a service worker use a CSP like:

default-src self; image-src *; connect-src use-original-destination;

This would give the service worker a more restrictive policy than what it would need otherwise:

default-src self; connect-src *;

And it would not open up the XSS for pages unless they opt-in to the "use-original-destination" policy.

@wanderview
Copy link
Member Author

@annevk pointed out in IRC that this still would not help since the service worker controls the page and can arrange for any destination request it wants. So it would be a false sense of protection.

I'll leave this open for now since others seemed interested, but I'm mostly convinced its WONTFIX now.

@annevk
Copy link
Member
annevk commented Aug 17, 2018

Closing this given the lack of further input. The only way to do this is creating a new kind of response and that'd be quite involved for not that much benefit.

@annevk annevk closed this as completed Aug 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants
0