Skip to content
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

Responding to cross-origin requests using a worker? #130

Closed
FremyCompany opened this issue Dec 3, 2013 · 23 comments
Closed

Responding to cross-origin requests using a worker? #130

FremyCompany opened this issue Dec 3, 2013 · 23 comments

Comments

@FremyCompany
Copy link
Contributor

I was wondering how this situation was possible:

  • There's no harm in responding to a cross-origin request with a new SameOriginResponse() that you create out of thin air. Since the document in question is the thing that's at risk, and since the other APIs available to you won't allow you undue access to cross-origin response bodies, you can pretend you're any other origin -- so long as the only person you're fooling is yourself.

It seems to me that a service worker can only reply to requests to its own server, and all those requests are by definition same-origin.

Or can a worker installed from "domain.com" reply to a request of "a.domain.com" to a resource of "b.domain.com"? Even if so, my interpretation is that the "same origin" in this case is still "b.domain.com" and not "a.domain.com" or "domain.com".

What was the intent here?

@alecf
Copy link
Contributor

alecf commented Dec 3, 2013

There's a subtle difference between simply responding to a cross-origin request and responding to a cross-origin request that is embedded in a same-origin page.

ServiceWorkers handle the latter case: If a given page at http://domain.com/ requests http://a.domain.com/img.jpeg, then a service worker registered for "http://domain.com/*" will have the opportunity to intercept.

On the other hand, if a page at http://a.domain.com/index.html requests http://domain.com/img.jpeg, then that same service worker will NOT be invoked. The pattern matches the toplevel document, NOT the subresource.

(And you can substitute a.domain.com for any other domain like foo.com as well)

@alecf alecf closed this as completed Dec 3, 2013
@devd
Copy link

devd commented Dec 4, 2013

I assume iframes are a special case here? You don't want the service worker to fake data whose "src" is set to a different origin?

@tgvashworth
Copy link

There's some confusion around this issue – @jakearchibald said, during my ServiceWorker talk on Thursday, that the worker can intercept x-origin requests, but the API for manipulating responses will be severely limited.

I'll open an issue to explicitly clarify.

@tgvashworth
Copy link

Actually, looking again, the spec has something to say on this:

What if an app wants to cache items that come from a CDN or other domain? It's possible to request many of them directly using script, img, video and link elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it's possible to XHR many sorts of off-domain resources when appropriate CORS headers are set.

The implication there is that, becuase not being able to make different-origin resources offlineable would be very limiting, they can be intercepted by fetch events.

@piranna
Copy link

piranna commented Dec 14, 2013

I'm starting to get confused... If a.com set a SW, could a page on
b.comload an image (or better, do an XHR) on
a.com using the SW, or not? If not, why? And if yes, how it's suposed to be
done?
El 14/12/2013 21:01, "Tom Ashworth" notifications@github.com escribió:

Actually, looking again, the spec has something to say on thishttps://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md#cross-origin-resources
:

What if an app wants to cache items that come from a CDN or other domain?
It's possible to request many of them directly using


Reply to this email directly or view it on GitHubhttps://github.com//issues/130#issuecomment-30586803
.

@tgvashworth
Copy link

Not certain of what you mean, but I think the answer is this:

ServiceWorkers are able to make requests according to the same security restrictions as a page. So, they can make a x-origin request (xhr, importScripts or fetch) the same as the page, but the response will restricted in the same way it would be in the regular page – CORS headers and CSPs apply.

I'm not entirely clear on whether a resource request from a.com's ServiceWorker to a resource on b.com would hit the ServiceWorker that b.com has registered.

Edit: Actually, on second thoughts, I am. Your ServiceWorker, when requesting a resource from another domain, will not hit that domain's ServiceWorker: there's no document to associate the ServiceWorker with - it's just a resource request.

@piranna
Copy link

piranna commented Dec 14, 2013

I'm not entirely clear on whether a resource request from a.com's
ServiceWorker would hit b.com's ServiceWorker.

We should crearly define this point, then.

I'm not talking about having both a.com & b.com their own SW what would
answer to the request, I'm talking about being b.com a totally random web
page could access to a.com's SW the same way that it can access to a public
web service, and also without noticying that in fact it's answering a local
SW instead of a real web server. Regular web services can allow to do this
thanks to CORS, and I believe this will (or should!) be able to do with SW
too (if not directly, at least adding the CORS headers on the SW response),
but from the latest messages I'm starting to think maybe I misunderstood
how SW work, or maybe someone has found some security issues I can't be
able to identify... :-/

@tgvashworth
Copy link

Ah. Cross-origin ServiceWorkers are a definite no-no:

The reasons for this restriction is that ServiceWorkers create the opportunity for a bad actor to turn a bad day into a bad eternity. Imagine an XSS vulnerability anywhere on a site. An attacker that can run a bit of JS can now request a new ServiceWorker be installed. If that ServiceWorker is registered from different origin (say, evil.com), the ServiceWorker itself can prevent updates to content which might dislodge it. Worse, the original application wouldn't be able to help the users who have been stranded.

There's some notes underneath this, but for now it's best to assume no, afaik.

@piranna
Copy link

piranna commented Dec 14, 2013

That link and paragraph talks about installing a SW hosted on a different
domain. That's not what I'm talking about.

What I'm talking about is if a domain (for example, 'shop.com') install a
SW (registered at '/*') to cache it's content or queue request while
offline or whatever other thing, and later a request is done by another
domain that knows nothing about SW (for example, 'santalist.com') to a path
of that previously installed SW (for example, 'shop.com/api' or '
shop.com/images'), does the request will be routed by the 'shop.com' SW,
maybe using CSP or CORS headers? If not, will the SW (or the browser
itself) raise an error, or the request will be done to the real web server
instead, and why?
El 14/12/2013 22:27, "Tom Ashworth" notifications@github.com escribió:

Ah. Cross-origin are a definite no-nohttps://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md#cross-origin-serviceworkers
:

The reasons for this restriction is that ServiceWorkers create the
opportunity for a bad actor to turn a bad day into a bad eternity. Imagine
an XSS vulnerability anywhere on a site. An attacker that can run a bit of
JS can now request a new ServiceWorker be installed. If that ServiceWorker
is registered from different origin (say, evil.com), the ServiceWorker
itself can prevent updates to content which might dislodge it. Worse, the
original application wouldn't be able to help the users who have been
stranded.

There's some notes underneath this, but for now it's best to assume no,
afaik.


Reply to this email directly or view it on GitHubhttps://github.com//issues/130#issuecomment-30589115
.

@tgvashworth
Copy link

Looks like you missed the edit on my comment:

Your ServiceWorker, when requesting a resource from another domain, will not hit that domain's ServiceWorker: there's no document to associate the ServiceWorker with - it's just a resource request.

@piranna
Copy link

piranna commented Dec 15, 2013

Yes, I missed your edit, sorry. So, seems that the answer is "no" :-/ This
would be the easiest implementation, but I don't think this would be the
desired behaviour: it's not symetric with the one using real servers, and
also would limit the usage offline when needing to do request to a CORS
request an external web service that could perfectly be done by the
corresponding external ServiceWorker.

Send from my Samsung Galaxy Note II
El 15/12/2013 11:20, "Tom Ashworth" notifications@github.com escribió:

Looks like you missed the edit on my comment:

Your ServiceWorker, when requesting a resource from another domain, will
not hit that domain's ServiceWorker: there's no document to associate the
ServiceWorker with - it's just a resource request.


Reply to this email directly or view it on GitHubhttps://github.com//issues/130#issuecomment-30601694
.

@tgvashworth
Copy link

S'all good.

Yep – no it is, and I'm not sure I agree this is not desired. The point of ServiceWorker is that it's associated with one or more documents, and enables you, as the application author, to have programmatic access to durable caches and network access associated with your application.

The use-case you talk about, where your app links to a resource of another application, doesn't make sense for that model. There are kind of two answers, imo:

  1. You can cache those third-party resources to rely on them. Their access would still adhere to the HTTP caching in the browser – but relying on that third party's ServiceWorker to have enabled your offline access to the resource is a bad model.
  2. It's good wisdom to not rely on a resource you don't control. I think this applies to the above.

@piranna
Copy link

piranna commented Dec 15, 2013

Yep – no it is. I'm not sure I agree this is not desired. The point of ServiceWorker is that it's associated with one or more documents, and enables you as the application author to have programmatic access to durable caches and network access associated with your application.

But what's happen if I'm developing and app, and want to offer my functionality to other apps? I could be able to use WebIntents and so, but the easiest way it's having a REST API. This require to have a web server, and the user to be online, but some functionality could be also being done client side.

The use-case you talk about, where your app links to a resource of another application, doesn't make sense for that model. There are kind of two answers, imo:

I'm not so much interested on my app linking to a resource of another application, but instead on offer that resource to other apps without needing a central web server/web service, and how could I make it as easy as possible to link it to the ones that want to do it (a plain HTTP request would be ideal). Allowing to my app to install a ServiceWorker that others could use (one thing I've always though it was possible to do from my interpretation of the spec) is the best and easiest solution to do it.

  1. You can cache those third-party resources to rely on them. Their access would still adhere to the HTTP caching in the browser – but relying on that third party's ServiceWorker to have enabled your offline access to the resource is a bad model.

I can't be able to cache the content when it's dinamically generated. On my personal use case, I intent to use the ServiceWorker as the entry point for a WebRTC based P2P network. This service worker would be "running" on background just like UNIX services or daemons do (as I always understood ServiceWorkers would work), but also random "client apps" (the third party, cross origin web pages) could connect to that "daemons" sending request to their REST APIs, only that instead of being processed by real web servers, since the "daemon" ServiceWorker is installed it could intercept and process the fetch and decide itself if it should do a real request to the web server, send it from it's own cache, or as in my personal use case, generate the response dinamically (in my case, add a file to the download queue, or fetching the content from the P2P network).

I have been testing and asking for several alternatives, and ServiceWorkers allowing fetch request from third party web pages (the "client apps") is the easiest, powerful and elegant of the solutions. In second place is ask to the user to run the service in a localhost server (if written in Node.js, the code would be almost the same, only difference would the context, a ServiceWorker vs an independent process), that's not so easy nor usually you have the system permissions to do it, and the third one is about requesting to the user to install a browser plugin similar to the Ubuntu Unity integration one instead of a ServiceWorker, that you could agree it's fairly worst not only from the user experience point of view (install a plugin? For what? No, thanks) but also for developers (not transparent integration, one plugin per browser...).

  1. It's good wisdom to not rely on a resource you don't control. I think this applies to the above.

It falls in the same area of REST web services, that if it's down, it doesn't work and request fails. Only difference is that the request is procesed locally by a CORS ServiceWorker instead of remotely by a CORS web service.

@jakearchibald
Copy link
Contributor

@devd Yeah, ifames are a navigate, not a resource fetch, so they'll act like full-page navigates.

@jakearchibald
Copy link
Contributor

Just to confirm, if you make a cross-origin request from a page, it will go through the service worker that manages the page. If there's a service worker registered for the url on the other domain, it will not go the other domain's service worker.

I'm open to use-cases here, but I don't think @piranna's REST example is one.

Say your site, http://example.com, which has a service worker, makes requests to http://api.jakearchibald.com, which also has a service worker.

Let's assume that unhandled requests go through the service worker of the other domain (which they don't). First problem: how is the service worker registered for http://api.jakearchibald.com? Perhaps the root page of http://api.jakearchibald.com contains:

<script>navigator.registerServiceWorker('/*', 'ctrl.js');</script>

…but who visits the root page of an API domain? Maybe you'd have a hidden iframe on your page pointing to http://api.jakearchibald.com to bootstrap the worker. There's a better way to get this behaviour already, in your worker you'd include:

importScripts('http://api.jakearchibald.com/ctrl.js');

…which would add listeners for it's API. This means it hears about all fetches, question is if this is any more dangerous than adding a script file from http://api.jakearchibald.com/ onto your page.

@piranna
Copy link

piranna commented Dec 16, 2013

Say your site, http://example.com, which has a service worker, makes requests to http://api.jakearchibald.com, which also has a service worker.

Ok, I see where's the problem: it's like you said, only that in my use case, example.com does NOT have a service worker, the only one here is the SW from apo.jakearchibald.com.

Let's assume that unhandled requests go through the service worker of the other domain (which they don't). First problem: how is the service worker registered for http://api.jakearchibald.com? Perhaps the root page of http://api.jakearchibald.com contains:

<script>navigator.registerServiceWorker('/*', 'ctrl.js');</script>

…but who visits the root page of an API domain?

Really good question... You are assuming API is on 'api.jakearchivald.com' (a sub-domain), but what about being the API endpoint at 'jakearchivald.com/api'? This way it could work, both registering the SW at '/*' or better at '/api' (that's what I was thinking for)...

Maybe you'd have a hidden iframe on your page pointing to http://api.jakearchibald.com to bootstrap the worker.

Little hackerish, isn't it? :-/

There's a better way to get this behaviour already, in your worker you'd include:

importScripts('http://api.jakearchibald.com/ctrl.js');

…which would add listeners for it's API. This means it hears about all fetches, question is if this is any more dangerous than adding a script file from http://api.jakearchibald.com/ onto your page.

Here you asume that the dev of example.com would include the api script of jakearchivald.com, but my intention is to be used from elsewere, also as links on a forum or similar.

I'm with exams, but I'll try to find some time to do a thoroughly in detail explanation of my use case and publish it so we can all be sure we are talking about the same, and also you could send me suggestions if you think there are better solutions.

@jakearchibald
Copy link
Contributor

Say your site, http://example.com, which has a service worker, makes requests to http://api.jakearchibald.com, which also has a service worker.

Ok, I see where's the problem: it's like you said, only that in my use case, example.com does NOT have a service worker, the only one here is the SW from apo.jakearchibald.com.

That doesn't matter, the issues I point out still apply even if the page's domain doesn't have a service worker at all.

You are assuming API is on 'api.jakearchivald.com' (a sub-domain), but what about being the API endpoint at 'jakearchivald.com/api'? This way it could work, both registering the SW at '/*' or better at '/api' (that's what I was thinking for)...

Not really, you're still depending on a visitor to your site having visited mine in order to get the worker registration.

Here you asume that the dev of example.com would include the api script of jakearchivald.com, but my intention is to be used from elsewere, also as links on a forum or similar.

Links on a forum would be fine, as clicking a link causes a navigation, so that will use the service worker of the destination url.

@piranna
Copy link

piranna commented Dec 16, 2013

Say your site, http://example.com, which has a service worker, makes requests to http://api.jakearchibald.com, which also has a service worker. Ok, I see where's the problem: it's like you said, only that in my use case, example.com does NOT have a service worker, the only one here is the SW from apo.jakearchibald.com.

That doesn't matter, the issues I point out still apply even if the page's domain doesn't have a service worker at all.

Ok.

You are assuming API is on 'api.jakearchivald.com' (a sub-domain), but what about being the API endpoint at 'jakearchivald.com/api'? This way it could work, both registering the SW at '/*' or better at '/api' (that's what I was thinking for)...

Not really, you're still depending on a visitor to your site having visited mine in order to get the worker registration.

Ok, I agree on the fact the visitor has navigated previously to get the worker registration (I've assumed it was done anyway...).

Here you asume that the dev of example.com would include the api script of jakearchivald.com, but my intention is to be used from elsewere, also as links on a forum or similar.

Links on a forum would be fine, as clicking a link causes a navigation, so that will use the service worker of the destination url.

Truly? Also for redirections done by registerProtocolHandler (in the end, my use case)? That are good news :-) Would it also work for linked images on a forum? And for XHR (this last would be awesome... :-) )?

@jakearchibald
Copy link
Contributor

Nah, any requests which are part of the page (images, xhr, js, css etc) will go through the serviceworker of the current page. For registerProtocolHandler, if it redirects to an http(s) page, it'll use the serviceworker of the destination page.

@piranna
Copy link

piranna commented Dec 16, 2013

Nah, any requests which are part of the page (images, xhr, js, css etc) will go through the serviceworker of the current page. For registerProtocolHandler, if it redirects to an http(s) page, it'll use the serviceworker of the destination page.

Great then, I think I could do it the way I intended (registerProtolHandler
redirecting to a HTTP resource managed by the destination ServiceWorker),
anyway I'll take a look when we could start hacking on it to see if it's
still possible.

By the way, we should write clear this points and this definitions
(destination page, destination SW...) so this kind of use cases and corner
cases can be managed easier.

@tgvashworth
Copy link

@piranna – would you mind replying on Github? Your email replies are very hard to read!

@piranna
Copy link

piranna commented Dec 16, 2013

Sorry @PhUU, I didn't know they were looking so ugly. I'll do it here from now.

@Pacerier
Copy link

Pacerier commented Oct 15, 2017

@jakearchibald, @ all; Anyone can solve chrome ext crossorigin serviceworker?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants