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

Feature request: Provide a way to delay execution of a new service worker #1208

Open
twiss opened this issue Oct 16, 2017 · 9 comments
Open

Comments

@twiss
Copy link
Member

twiss commented Oct 16, 2017

[I also posted about this on the mailing list, but I didn't receive any replies and I feel that this is important. Sorry if it comes across as spam.]

It would be nice if it were possible to reliably make a request from the updatefound event. Currently, if the new Service Worker calls skipWaiting(), the old Service Worker gets killed and its request canceled in both Chrome and Firefox, with no way to avoid it, because updatefound is not an ExtendableEvent.

Why? I'm trying to use Service Workers to solve the quite old and fundamental problem that on the web, you can't make applications that don't trust the server (and e.g. use client-side encryption) because the server sends you the code every time you open it. Basically, with Service Workers, I'm serving the code from SW cache instead, and only updating it if it matches some public log (in my case GitHub), in effect achieving some form of Binary Transparency on the web.

But, of course, the SW can update at any time. So, to make it secure, we need to check the new SW against GitHub as well, in the updatefound event, and warn the user if it doesn't match. (Of course, we can't prevent the update, but we can at least try to convince the user to close the web app before it steals their private keys.)

@jakearchibald
Copy link
Contributor

This is totally the correct place to make this feature suggestion.

You're not the first to suggest features that make the SW somehow resistant to updates. The problem is, the same feature could be used by a malicious service worker to prevent removal.

At the moment, we guarantee that if the worst happens, and someone gets an evil service worker installed on your origin, you can undo the damage at the next update check. If the bad guy managed to set a long max-age on the script, it'll be capped to 24hrs.

@jakearchibald jakearchibald changed the title Feature request: Make updatefound an ExtendableEvent Feature request: Provide a way to conditionally prevent a service worker update Nov 2, 2017
@twiss
Copy link
Member Author

twiss commented Nov 2, 2017

Hi @jakearchibald, thanks for your response.

I'm not requesting the ability to prevent a Service Worker update, only the ability to delay it slightly. If the old Service Worker calls waitUntil with a promise that takes too long, say more than a few minutes or so, I'm perfectly fine if it gets killed and updated.

That last part is already allowed by the spec, I think: "However, the user agent may impose a time limit to this lifetime extension."

Basically, all I want to do in the updatefound event is make one or two network request and conditionally warn the user about the update.

@jakearchibald jakearchibald changed the title Feature request: Provide a way to conditionally prevent a service worker update Feature request: Provide a way to delay execution of a new service worker Nov 3, 2017
@jakearchibald
Copy link
Contributor

Ahh, sorry for misunderstanding!

@jakearchibald
Copy link
Contributor

Btw #822 relates to preventing updates.

@jakearchibald
Copy link
Contributor

Also similar #761

@twiss
Copy link
Member Author

twiss commented Nov 4, 2017

Thanks, I hadn't seen those. The use case in #822 (comment) is basically the same as mine, namely, 1) a web app that handles potentially sensitive user data and doesn't send it to the server, or only does so after encryption, and 2) wants to verify that all updates to the web app are authenticated. Together, those things move the web app from "trust the server every time you open it" to trust-on-first-use.

The only thing that differs is what happens when an update is not authenticated:

  1. With Preventing server-forced updates #822, the update wouldn't happen. That's the most fool-proof, but it allows developers to shoot themselves in the foot and render their web app broken.
  2. In my proposal, we show the user a big fat warning and try to convince them not to refresh the page.
  3. Another idea is to add some "Do you want to update this web app? [Keep this version] [Update]" UI to the browser that the SW can trigger. That might even be useful for non-security-related use cases.

One issue to consider is, what happens if there is no open/visible client of the Service Worker? That can happen if a third party origin loads the web app in an iframe (and either hides it, or the web app responds with X-Frame-Options: deny). It can also happen when the SW receives a push event, although that can be prevented ahead of time by.. not registering for push events. It might be an issue for, say, encrypted chat apps though.

One option if we go with option 2 above, is to request permission for Web Notifications ahead of time. Then, we can always warn the user in the updatefound event. However, it's probably unwise to rely on users to grant that permission for security warnings. Another option is to not update the Service Worker if the web app responds with X-Frame-Options: deny (related Chrome and Firefox bugs).

Similarly, with option 3 above, we could default to not updating if there is no open client.

@twiss
Copy link
Member Author

twiss commented Jan 18, 2018

I think I've found a workaround to this issue: instead of calling (the nonexistent) waitUntil in an updatefound event, call waitUntil from a preceding functional event (e.g. fetch).

I believe all Service Worker updates will be preceded relatively shortly by a functional event, be it a fetch event during the page load which triggered an update, or a functional event that itself triggered the update, although it's not guaranteed: "The user agent may call [the Soft Update algorithm] as often as it likes to check for updates." (Please correct me if I'm wrong and browsers actually do this.)

Another downside is that, AFAICT, you have to register for all known functional events, because if you don't and it fires, the Service Worker is updated but not started (https://w3c.github.io/ServiceWorker/#handle-functional-event-algorithm, step 4.2). That is of course impractical and bad for performance (since the SW is uselessly started and made to keep running with waitUntil() if an update isn't found), so it would still be nice to have waitUntil() on updatefound events. (And also because, as mentioned, this workaround is not guaranteed to be correct.)

@MisterTicot
Copy link

This would be solved by this proposal: #822 (comment)

@elimisteve
Copy link

Hi all,

I just wanted to say why I think some version of this proposal would have a very positive impact on the future of the web:

  1. Firstly, I agree with your reasoning behind preventing a Service Worker (SW) from blocking updates to itself indefinitely.  Unlike Preventing server-forced updates #822 and Allow preventing the update process to finish #761 , this proposal does not suggest preventing SWs from being updated for a significant period of time (and certainly not indefinitely).

  2. Many of us would love to see the web become more trustworthy, at least for sites that choose to implement what @twiss is trying to enable.  By allowing web app creators to guarantee to users that they (the users) are not running a different, perhaps-malicious version of a web app than other users on the same site, and by being able to warn users when an unauthorized version of said web app's JavaScript is about to be executed, this greater trust can be achieved.

  3. As a web developer, if I deploy a buggy SW, I want to be able to replace it quickly.  IIUC, the latest version of his proposal merely seeks to guarantee that a small window of time exists (e.g., 60 seconds) for the old SW to somehow warn the user that a possibly-malicious SW is about to replace it.

By providing this guarantee via the spec, you will enable a decades-long dream of web developers to come true -- for it to be possible to build web applications that are approximately as trustworthy as native apps, arguably more so, since web apps cannot run around on the user's hard drive to wreak havoc, but are instead trapped in the browser.

And for the majority of web apps who don't need such high security, they will remain unaffected.

Would love to see some version of this get accepted! 👍

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

No branches or pull requests

4 participants