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

Header for dissalowing SW registration (and implicitly removing SWs)? #224

Closed
slightlyoff opened this issue Apr 8, 2014 · 29 comments
Closed

Comments

@slightlyoff
Copy link
Contributor

Pending discussion of CSP policy, it seems as though we should either craft the CSP support in such a way as to dissalow registration of SW's based on header (e.g., so that rawgithub.io can continue to function) and potentially unregister existing SW's when it encounters such a directive.

/cc @jakearchibald @mikewest

@slightlyoff
Copy link
Contributor Author

Will attempt to capture the major issues involved here. First, background for those just tuning in:

  1. Service Workers are same-origin-only. That is, the script that is registered must be served from the registering origin. It may subsequently use importScripts() to compose x-origin scripts, but as a mitigation against 3rd parties (or transient, hostile first parties) the SW script itself must remain under control of the source origin.
  2. Service Workers are HTTPS only. See SSL/TLS Only? #199 for discussion. This mitigates the risk of hostile portals, etc.
  3. The max cache duration for SW scripts is 1 day. Past that mark, the UA will go to the network to try to fetch a new script. This is meant to help mitigate against intermittent failure/pwnage.

The remaining threats revolve around compromised same-origin content. The naive version of this (which has been discussed at length) is the university homedir scenario. It's already the case that this content has full authority relative to other content on the origin, but SW's potentially exacerbate this.

Another scenario worth considering is a transient pwning: a malicious SW could be served from the location of an (otherwise valid) image URL. Since it won't successfully update once the hole is closed, it may appear silent to site owners and users might be pwn'd for a long time. It was proposed at one point to remove SWs on 4xx responses, but this doesn't address the correct-but-doesn't-parse cloaking (and significantly complicates multi-datacenter rollouts).

The proposed mitigations for these scenarios are:

  1. a header that's sent with the request for the SW script identifying it as such. Combined with the 24 hour max age for pings, this should help administrators keep the window of vulnerability small and provide a path to remediating issues once discovered.
  2. potential extensions to CSP to control which bits of URL space are allowed to register SWs. SWs will respect the script-src attribute already, but separate control may be desirable to disable SWs only as they have the power to more persistently affect content.

@johnmellor
Copy link

It doesn't seem like the header would help for a shared host (e.g. university homedirs) that allows directories to set their own headers, e.g. using PHP.

How about instead having the highest allowed SW scope be set by the path of the SW? For example, if the SW is hosted at https://example.com/sw.js, then https://example.com/foo/bar.html should be allowed to register that SW for any same-origin scope, including '/*'. But if the SW is hosted at https://example.com/foo/sw.js, then the highest allowed scope would be '/foo/'. Thus you would only be able to intercept content in the same directory or subdirectories of the location of the SW, which it is more likely that the author of the SW already has access to.

@jyasskin
Copy link
Member

It's a tricky problem. Limiting the scope to be under the current path, with no escape via a header, would prevent sites like https://mail.google.com/mail/u/0/, https://github.com/slightlyoff/ServiceWorker/issues, and http://www.yelp.com/biz/the-original-ghirardelli-ice-cream-and-chocolate-shop-san-francisco from registering a single service worker for their whole site given a deep link. They'd probably have to redirect through the root on every request that didn't already have an active service worker.

Using a header to set a more permissive maximum scope would leave the university sites broken, but it might let more sites like rawgit.com keep working by default.

I suspect @slightlyoff prefers the opposite default at least partly because https://tools.ietf.org/html/rfc6454#section-3.4.3 recommends against trying to subdivide origins.

However, I'm still worried about the now-stronger requirement that sites need to isolate each user to their own sub-domain or serve this new header. What fraction of the web is this going to make exploitable?

@jakearchibald
Copy link
Contributor

Limiting the scope to be under the current path, with no escape via a header, would prevent sites like

I think @johnmellor is proposing preventing registration for scopes parent to the service worker js file, not scopes parent to the registering page. It does solve the homedrive issue. Being able to put a file there becomes "proof" of ownership.

Pretty sure we had a discussion about this already, but can't find it. Here are the issues:

  • Restrictive over worker urls - if you want to control "/*", your worker must be at the root
  • The default value for scope becomes a poor default, although its default could be determined by the worker url. For "/whatever/worker.js" the default scope would be "/whatever/*". This could be a gotcha.

@jakearchibald
Copy link
Contributor

As for the SW CSP stuff, there's a discussion over at #113

@devd
Copy link

devd commented Apr 23, 2014

I vote for sticking to origin based policies and a HTTP header to allow/disallow registrations. https://tools.ietf.org/html/rfc6454#section-3.4.3 is based on a number of previous bad experiences trying to get anything more finer-grained than origins.

Lets stick to origins and if sites want finer-grained isolation, then can use sub-origins http://www.chromium.org/developers/design-documents/per-page-suborigins

@slightlyoff
Copy link
Contributor Author

Fundamentally insecure sites that don't control outbound headers can't be helped, I think. Nearly all other origin-based resources (IDB, storage, etc.) can be poisoned. Restricting SWs here only changes the scope of the poisoning.

I'd previously considered the path restriction (can't quickly find the bug where I proposed it) but ended up deciding against it based on the ability of evil content on an origin to screw with so many other aspects of content for that origin. The argument from defense in depth is intresting to me, though.

/cc @jakearchibald @jungkees @mikewest

@johnmellor
Copy link

Nearly all other origin-based resources (IDB, storage, etc.) can be poisoned.

Poisoning at least requires you to find a vulnerable script that reads and evals (or similar) a value from storage. Whereas installing a SW grants you god-mode on all future requests to the origin.

If we don't want to split origins based on paths (and I understand there are good reasons for this), then perhaps the best mitigation is to require Service Worker scripts to always be located in the root directory?

@piranna
Copy link

piranna commented Apr 25, 2014

This would difficult usage... What about like CSS, where paths are relative
to the CSS file? We would forbit to register a SW in a path lower that the
SW or the current page, whatever of both is lower...

@slightlyoff
Copy link
Contributor Author

@piranna : agreed.

The better alternative (which I had previously considered) is to not allow the page to register for a scope broader than it's current-path-component + "/*". Constraining the location of the script itself doesn't buy you much. The real issue is the scope. There will always be ways to trick a well-written worker script into doing "bad" things when under the control of an attacker. The only meaningful defense is to ensure that attackers can only attack themselves.

The path restriction on scope has the benefit of perhaps enabling sites like github.io from not needing to freak out as soon as a browser supports SWs. Have opened #253 to discuss further.

I'd like to refocus this issue on design for headers for detection/remediation/control. We clearly need them as well.

@annevk
Copy link
Member

annevk commented Apr 27, 2014

I don't see how the CSS argument makes sense. If it is associated with a document and that document is associated with a service worker, that service worker will see all requests.

@piranna
Copy link

piranna commented Apr 27, 2014

I asking about using a similar scheme to how CSS works, where the referenced paths (for example for images) are relatives to the CSS file. In that case, paths would be relatives to the SW file. This way we can use the same SW from /foo/index.html and /foo/blah/index.html, being for example the paths to the SW utils/sw.js and ../utils/sw.js respectively. Later, we can set that the SW can't be able to manage content in a lower level of the top common path, in that case, SW could manage anything on /foo/* since the /foo path frament in common for both, but on /*. Is it my idea more clear now?

@annevk
Copy link
Member

annevk commented Apr 28, 2014

No.

@jkarlin
Copy link

jkarlin commented Jun 30, 2014

Chromium now appends a 'Service-Worker: script' header to SW script requests (but not its imports). This header can be used by administrators to block registrations. Is such a header still considered necessary or useful?

@annevk
Copy link
Member

annevk commented Jun 30, 2014

Cannot really think of a good reason why in the TLS-only, same-origin world.

@jyasskin
Copy link
Member

This sort of header would be useful for detecting and recovering from XSS, which is still a risk in the TLS-only world. I have to defer to @metromoxie, etc. to say whether this particular header is the right way to do it.

@annevk
Copy link
Member

annevk commented Jun 30, 2014

How would you inject a service worker? It has to be a networked same-origin resource. We will likely add the ability to disable service workers through CSP. They have their own request context.

@jakearchibald
Copy link
Contributor

The attack would require:

  • User can execute script on the origin
  • User can create context that successfully parses as JavaScript
  • Site doesn't use CSP on every page to prevent SW registration

An example of this would be a comment on an article that allows script execution, and also has an endpoint on the origin that displays the comment content.

Setting a CSP directive after the attack doesn't work. The site owner would need to identify all the locations users are requesting serviceworkers from, and return an serivceworker that unregisters itself.

In the past I've suggested requiring a valid javascript mime type for serivceworkers to reduce the possibiility of this attack.

As for the header itself (if we still think we need it), I think Context: serviceworker fits in better with the fetch spec.

@annevk
Copy link
Member

annevk commented Jul 1, 2014

Were we not going to require a valid JavaScript MIME type for service workers?

@annevk
Copy link
Member

annevk commented Jul 1, 2014

(If we do end up needing a header here, per http://lists.w3.org/Archives/Public/ietf-http-wg/2010OctDec/thread.html#msg105 there's something called a Purpose header, but maybe the semantics are slightly off.)

@jakearchibald
Copy link
Contributor

Oh, didn't realise we decided on requiring a JS mime type. Makes sense to me. Great.

So, I guess the remaining "attack" is a homedir system where the origin gets sericeworker'd because the site owner didn't set CSP to block serviceworkers. They'd need to find all the SW update requests and serve an unregistration script.

Would it be easier if the "no serivceworker" CSP header also unregistered serviceworkers? Those headers can't be spoofed when checking the SW for updates.

@annevk
Copy link
Member

annevk commented Jul 2, 2014

Yeah, if you have a CSP network level header that forbids SW, it would make sense if any existing SWs for that origin were nuked.

@jakearchibald
Copy link
Contributor

Not sure nuking all on the origin makes sense, but certainly registrations using that use that url for SW updates.

@jyasskin
Copy link
Member

I talked to @slightlyoff, and I think we both came away believing that if:

  1. There's a Service Worker with a scriptURL of https://example.com/foo.js, and
  2. When foo.js is requested in the [[Update]] algorithm, if the response includes a CSP header that disallows Service Workers, then the SW is immediately unregistered, and
  3. This CSP header supports report-uri so the server operator can learn about the set of active malicious paths,
    then the Service-Worker: script header adds nothing over the CSP system.

@slightlyoff made the point that we need some XSS-recovery technique before shipping Service Workers, that we want to ship SWs soon, and that something like the Service-Worker header is likely to be ready before the CSP spec can be updated, so it's a good idea to include the Service-Worker header in the shipped SW spec.

I'm curious if the folks implementing this and the CSP spec editors agree with Alex's estimate of the timelines. It'd definitely be nice to only ship one way of doing the same thing.

@jakearchibald
Copy link
Contributor

@mikewest how quickly do you think we can get CSP to block serviceworker?

We're looking for a header to block registrations & unregister if the header appears on updates. Feels uncontentious to me.

@jyasskin
Copy link
Member

I've started a thread on webappsec to talk about the CSP approach to this. I think that's independent of whether to include the Service-Worker: script header until the CSP approach is agreed on and implemented, but it's good to get the ball rolling toward the long-term solution regardless.

@slightlyoff
Copy link
Contributor Author

I think we should keep including this (or something like it) in order to
aid logging and recovery no matter what.

On Mon, Jul 21, 2014 at 7:39 PM, Jeffrey Yasskin notifications@github.com
wrote:

I've started a thread on webappsec
http://lists.w3.org/Archives/Public/public-webappsec/2014Jul/0083.html
to talk about the CSP approach to this. I think that's independent of
whether to include the Service-Worker: script header until the CSP
approach is agreed on and implemented, but it's good to get the ball
rolling toward the long-term solution regardless.


Reply to this email directly or view it on GitHub
#224 (comment)
.

jyasskin added a commit to jyasskin/ServiceWorker that referenced this issue Jul 24, 2014
This is based on a suggestion in
http://lists.w3.org/Archives/Public/public-webappsec/2014Jul/0102.html which is
similar to a suggestion in
w3c#224 (comment).

The CH- prefix matches the Client-Hint pattern in a couple other specs, including CH-CSP.
Lower-case "serviceworker" matches the list of contexts in Fetch: http://fetch.spec.whatwg.org/#concept-request-context
jyasskin added a commit to jyasskin/ServiceWorker that referenced this issue Jul 24, 2014
This is based on a suggestion in
http://lists.w3.org/Archives/Public/public-webappsec/2014Jul/0102.html which is
similar to a suggestion in
w3c#224 (comment).

The CH- prefix matches the Client-Hint pattern in a couple other specs, including CH-CSP.
Lower-case "serviceworker" matches the list of contexts in Fetch: http://fetch.spec.whatwg.org/#concept-request-context
jyasskin added a commit to jyasskin/ServiceWorker that referenced this issue Jul 27, 2014
…vice Worker at that scriptURL.

Joshua Peek suggested that this should work
(http://lists.w3.org/Archives/Public/public-webappsec/2014Jul/0109.html)
because `sandbox` gives the resource a unique origin, which combines with
Service Workers' same-origin policy to disallow execution.

See w3c#113 and w3c#224.
jyasskin added a commit to jyasskin/ServiceWorker that referenced this issue Jul 29, 2014
…vice Worker at that scriptURL.

Joshua Peek suggested that this should work
(http://lists.w3.org/Archives/Public/public-webappsec/2014Jul/0109.html)
because `sandbox` gives the resource a unique origin, which combines with
Service Workers' same-origin policy to disallow execution.

See w3c#113 and w3c#224.
@KenjiBaheux KenjiBaheux removed this from the Version 2 milestone Aug 8, 2014
@KenjiBaheux
Copy link
Collaborator

I'll work on a draft to suggest how we should use the labels and milestones.
Let me make some adjustments based on how I believe we should use these:

enhancement: anything that was assessed as not having any impact on milestone 1 decisions and can therefore be safely discussed, rejected or prioritized later.

milestone: to mark items we agreed to get done in principle by a given revision. I would argue that we should only focus on the current milestone and leave the rest without specific milestones.

@jakearchibald
Copy link
Contributor

@mikewest Am I right in thinking the CSP that prevent service worker reg is child-src? Reopen if not.

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

9 participants