[whatwg/fetch] consider failing same-origin fetch requests that get a cross-origin cors Response synthesized by a service worker (#629)

At the service worker f2f at TPAC today we discussed the issue I raised here:

  https://github.com/whatwg/fetch/pull/146#issuecomment-341710548
  https://bugzilla.mozilla.org/show_bug.cgi?id=1222008#c39

To summarize, consider this use case:

```js
// main window
let outerResponse = await fetch(url, { mode: 'same-origin' });

// controlling service worker
addEventListener('fetch', evt => {
  evt.respondWith(async function() {
    let innerResponse = await fetch(crossOriginURL, { mode: 'cors' });
    return innerResponse;
  }());
});
```

For a long time we have allowed the service worker to synthesize the cross-origin CORS response on the same-origin FetchEvent.request.  The rationale was that the body could be read from the CORS response and used to create a completely synthetic Response, so it would be a toothless restriction.

At this point in history, though, the original request URL was maintained.  So `outerResponse.url === url` and `innerResponse.url === crossOriginURL`.

PR #146, however, then added a change that exposes the Response.url if its present instead of using the Request.url.  After this the example should result in values such that `outerResponse.url === innerResponse.url === crossOriginURL`.

Now, this seems somewhat innocuous for this `fetch()` example.  Consider, though, what this means for other same-origin network requests.

A top level worker script is required to be same origin.  If we allow a cross-origin CORS response to be synthesized for these scripts and expose the URL then we will result in a `self.location.href` that is of a different origin than `self.origin`.  Also, all importScripts() will relative to the other origin.

Its not clear that there is an attack vector here, but it is clearly unprecedented and quite weird.

Also, consider that the original argument for allowing cross-origin CORS responses for same-origin requests is no longer quite valid.  If script created a new synthetic Response the URL ends up as empty string and the Request URL is used instead.  The direct passing of the CORS response is not equivalent any more.

Also, passing the cross-origin CORS response for same-origin requests is inconsistent with other restrictions we have put in place.  Consider a manual redirect Request.  We fail these requests if you pass them a Responsed with .redirected true.  In general this is easily worked around by creating a new synthetic Response with the same body, but does not get the redirected flag set.  We still enforce the .redirected restriction, however, even though its just as toothless as the same-origin restriction we originally decided not to enforce.

Given all of this, during the face-to-face we came to the conclusion that it would be desirable to enforce the same-origin restriction.  If a service worker synthesizes a cross-origin CORS response on a same-origin Request then the fetch would be rejected with a NetworkError.

There is some question if this is too breaking or not at this point.  We need to collect some data to that end.

If its too breaking, though, I think we should consider using the Request.url if the Response.url is cross-origin and the Request.mode is same-origin.  This might be something we would consider doing in gecko in the short term while we collect usage data.

@annevk, what do you think?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/fetch/issues/629

Received on Wednesday, 8 November 2017 04:31:42 UTC