Disable Service Worker.

投稿日 2022/01/23

This article is a translation of the following Japanese article.

Introduction

ServiceWorker, a much talked about feature these days, has been added to the browser. This is a great feature that allows you to do functions like smartphone apps in the browser. It's a great feature that allows you to achieve smartphone app-like functionality in your browser. However, it can be registered without prior approval from the user.

ServiceWorker is a convenient but very dangerous feature because it allows you to perform smartphone app-like functions without approval. Anti-virus software (such as Windows Defender) may detect some ServiceWorkers as viruses. ServiceWorkers can continue to run even after the site is closed, which can make the browser slow. ServiceWorkers also store large amounts of cache, which can lead to disk and memory overload.

Check your registered ServiceWorkers

You can check them by accessing the following address. You can also unsubscribe manually.

// Chrome
chrome://serviceworker-internals

// Edge
edge://serviceworker-internals

// Firefox
about:serviceworkers
about:debugging#workers

It is not possible to manually unsubscribe from Google related services in Chrome.
It is possible to unregister Google related services in Chrome using the following method.

Deny ServiceWorker registration in user script.

By replacing the ServiceWorker registration function, new registrations will be rejected. Also, ServiceWorker can be unregistered.

Specifications

  • Replace the ServiceWorker's registration function to make new registration impossible.
  • If the ServiceWorker is already registered, it will be unregistered.
  • Clear the cache if the ServiceWorker is already registered.
  • Can be used as a whitelist by setting @exclude.
  • Complete rejection of registration is not possible with the timing of user script execution.
    • Due to a slight delay in inserting the script into the page
    • ServiceWorker will be registered temporarily, but will be unregistered immediately afterwards
      • However, if the unregistration is interfered with, it may not be possible to unregister
    • The extension version works more powerfully in this area than the userscript version.

User script code

RejectServiceWorker.user.js// ==UserScript==
// @name        RejectServiceWorker
// @description Reject to register a ServiceWorker.
//              Unregister the registered Service Worker.
//              If ServiceWorker was registered, it clears the cache.
//              You can use it as a whitelist by setting @exclude.
//              It is not possible to completely reject registration at the timing of executing the user script.
// @note        ↓↓↓ Add target page URL ↓↓↓
// @include     https://*/*
// @exclude     https://example.com/*
// @note        ↑↑↑ Add target page URL ↑↑↑
// @author      toshi (https://github.com/k08045kk)
// @license     MIT License | https://opensource.org/licenses/MIT
// @version     0.2.3
// @since       0.1.0 - 20200328 - 初版
// @since       0.1.1 - 20200415 - 修正
// @since       0.2.0 - 20200926 - Greasemonkey対応(unsafeWindow経由でwindowのオブジェクトを書き換え)
// @since       0.2.1 - 20210125 - RejectServiceWorkers.user.js → RejectServiceWorker.user.js
// @since       0.2.2 - 20210828 - comment メタデータの見直し
// @since       0.2.3 - 20211013 - comment 権限不足エラーの注意書きを追記
// @see         https://github.com/k08045kk/UserScripts
// @see         https://www.bugbugnow.net/2020/03/Reject-to-register-a-ServiceWorker.html
// @run-at      document-start
// @grant       unsafeWindow
// ==/UserScript==

(function(w) {
  // Reject to register a ServiceWorker
  if ('serviceWorker' in navigator) {
    w.ServiceWorkerContainer.prototype.register = function(scriptURL, options) {
      return new Promise((resolve, reject) => {
        //console.log('Reject to register a ServiceWorker.');
        reject(new Error('Reject to register a ServiceWorker.'));
      });
    };
    // Note: It may be registered before `document-start`.
    // Note: A permission error occurs on the page accessing the register() Promise in Firefox.
    //       This is because the context script Promise is accessed from the page script.
    //       I can't figure out how to get around this in user scripts.
    //       The WebExtensions version works around this.
  }

  // Unregister the registered Service Worker
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.getRegistrations().then((registrations) => {
      if (registrations.length != 0) {
        for (let i=0; i<registrations.length; i++) {
          registrations[i].unregister();
          //console.log('ServiceWorker unregister.');
        }
        caches.keys().then((keys) => {
          Promise.all(keys.map((key) => { caches.delete(key); })).then(() => {
            //console.log('caches delete.');
          });
        });
      }
    });
  }
})(unsafeWindow || window);
// Note: It is not working on Firefox (Tampermonkey / Violetmonkey) because of the following error.
//       Error "Uncaught (in promise) DOMException: The operation is insecure."
//       Use it with Firefox (Greasemonkey) or Chrome (Tampermonkey / Violetmonkey).

Block (or manage) ServiceWorker with an extension

The following extension has already been created. This is a feature that is still in its infancy, so there may be better ones if you look for them.

author's extension

It works in the same way as the above user script. The extension works more powerfully than the user script because the execution timing is faster.

etc.

Disable ServiceWorker in browser settings.

Chrome (cannot be disabled)

We have not found a way to disable ServiceWorker in Chrome. If you want to disable ServiceWorker in Chrome, it is best to use the above user script or extension.

Firefox

Firefox can disable ServiceWorkers by going to about:config and setting dom.serviceWorkers.enabled to false. However, it is necessary to unregister all ServiceWorkers from about:serviceworkers in advance, because already registered ServiceWorkers will still work.

※ You will need to restart Firefox to reflect the settings.

Remarks (Disable with script disable)

The registration of ServiceWorkers requires JavaScript. Therefore, you can reject ServiceWorker registration by disabling JavaScript.

Therefore, you can reject the registration of ServiceWorker by disabling JavaScript with NoScript.

If it is already registered, ServiceWorker will continue to work.

Remarks (Disabling Workers using CSP)

By adding a Content-Security-Policy (CSP) header or meta tag like the one above, you can block the Worker / SharedWorker / ServiceWorker source code as invalid code. As the source code of the worker, it will not be loaded.

In CSP, Worker/SharedWorker is also blocked.
 CSP cannot block only ServiceWorkers.
 CSP cannot block only ServiceWorker. Blocking Worker/SharedWorker may cause unstable page operation.
If you have already registered, the ServiceWorker will continue to work.
It also blocks the dataURL.

Example: uBlock Origin's filter

! Deny worker registration for some pages.
||example.com^$csp=worker-src 'none'

! Deny worker registration for all pages
*$csp=worker-src 'none' !
! Cancel denial of worker registration for some pages.
@@||example.com^$csp=worker-src 'none' !

Simple explanation

  • !: comment line
  • ||example.com^: Specify per-domain (including subdomains)
  • *: wildcard (all domains)
  • @@: cancel effect of filter (exception rule)
  • $csp=: Add a meta tag for Content-Security-Policy.
  • worker-src 'none': Set empty set for worker-src directive

Example: User script

BlockingWorkerWithCSP.user.js// ==UserScript==
// @name        BlockingWorkerWithCSP
// @description Use CSP to block Worker.
// @note        ↓↓↓ Add target page URL ↓↓↓
// @include     https://example.com/*
// @note        ↑↑↑ Add target page URL ↑↑↑
// @author      toshi (https://github.com/k08045kk)
// @license     MIT License | https://opensource.org/licenses/MIT
// @version     0.1.0
// @since       0.1.0 - 20210828 - 初版
// @see         https://www.bugbugnow.net/2020/03/Reject-to-register-a-ServiceWorker.html
// @run-at      document-end
// @grant       none
// ==/UserScript==

(function() {
  // Add CSP meta tag
  var meta = document.createElement('meta');
  meta.setAttribute('http-equiv', 'Content-Security-Policy');
  meta.setAttribute('content', "worker-src 'none'");
  document.head.appendChild(meta);
  // Note: This user script will block all Worker, not just ServiceWorker.
  // Note: It is not possible to stop a Worker that is already running.
})();

Simple explanation

  • Insert CSP meta tags into the target page.
  • The CSP meta tag blocks the loading of the worker source code.
    • If ServiceWorker is registered before the meta tags are inserted, it is not tested.
  • Blocks not only ServiceWorker but also Worker/SharedWorker.
  • Cannot stop a ServiceWorker that is already running

※ uBlock Origin is internally similar to user script.

Remarks (Disabling Cache only)

Let's consider how to disable only Cache while running ServiceWorker.

As it turns out, this is not possible at present. (It is more practical to disable ServiceWorker.)

At first glance, it seems that it is possible to override the Cache functions as well as the ServiceWorker registration functions. However, there is no way to override the Cache inside the ServiceWorker. Embedded scripts, user scripts, and extensions cannot override the ServiceWorker process.

The practical solution is to remove the Cache immediately, rather than disabling it. However, there is no event in place to notify you of cache changes such as the storage event. Therefore, deleting the entire cache every time the page is loaded and unloaded is a realistic approach.

However, if the ServiceWorker itself works on the assumption that the cached data exists, this may cause problems. This is not a problem if the ServiceWorker is flexible enough to perform a fetch operation when a fetch from the cache fails, but depending on the design of the ServiceWorker, the page will not work.

Code example (automatic deletion of the entire cache)

DeleteCache.user.js// ==UserScript==
// @name        DeleteCache
// @description Delete all caches.
// @note        ↓↓↓ Add target page URL ↓↓↓
// @include     https://example.com/*
// @note        ↑↑↑ Add target page URL ↑↑↑
// @author      toshi (https://github.com/k08045kk)
// @license     MIT License | https://opensource.org/licenses/MIT
// @version     0.1
// @since       0.1 - 20211231 - 初版
// @see         https://www.bugbugnow.net/2020/03/Reject-to-register-a-ServiceWorker.html
// @grant       none
// ==/UserScript==

(() => {
  const deleteCache = async () => {
    for (let key of await caches.keys()) {
      await caches.delete(key);
    }
  };
  window.requestIdleCallback(deleteCache);
  window.addEventListener('pagehide', deleteCache, {capture:true, passive:true});
})();

Remarks (Disabling ServiceWorker in mobile environment)

From the previous methods, you can disable ServiceWorker in a mobile environment if the extension can be installed. However, only some browsers allow extensions to be installed in the mobile environment. You can install the extension in the following browsers

  • Kiwi Browser (Android)
  • Firefox (Android)
  • Safari (iOS)

※ When ServiceWorker is disabled, A2HS (Add to Home screen) cannot be selected.
※ For Firefox (Android), only recommended extensions can be installed.
  Since uBlock Origin is available, the above CSP method can be used.
※ Reject Service Worker is not supported in Firefox (Android) / Safari (iOS).

Reference

コメント