Search code examples
javascripthttp-headersservice-workerspectresharedarraybuffer

Using service worker to enable COOP/COEP headers : security concerns?


I'm unable to access my server to enable COOP and COEP headers, but I was able to add them via service worker by using the following script https://github.com/gzuidhof/coi-serviceworker, which registers a service worker that has the headers active.

I need COOP and COEP to enable SharedArrayBuffer, which is restricted to avoid vulnerability to Spectre and Meltdown.

My question is whether adding the https headers via service worker poses a security risk, because the headers are not set at the server level.

At the bottom of this article, it argues that this is not a risk, https://dev.to/stefnotch/enabling-coop-coep-without-touching-the-server-2d3n

But I'd appreciate an explanation to better understand whether the service-worker approach is equivalently secure, or leaves open vulnerabilities.

Thanks!


Solution

  • Adding those headers via a service worker is equivalent from a security perspective, and it will enable equivalent functionality. There are a few things to keep in mind, though:

    • A service worker can't control a client page during the first time a user navigates to a site, or following a shift-reload. Setting these headers via the actual web server is the only way to guarantee that they will apply to those scenarios. Generally speaking, you should be careful to degrade gracefully if there are any features in your main web app that depend on the presence of a service worker.

    • There's a slight overhead involved with having a service worker controlling a page. If you were responding to requests by going straight to a local cache instead of the network, that would normally outweigh the overhead. Since it does not look like you plan on doing any caching in your service worker, you should feature-detect for navigation preloads and enable it if it's supported. This will mitigate the potential performance impact.

    • The headers only need to be set on responses that can create a client, like responses for documents or workers. I'd recommend checking in your service worker whether or not the request's destination is for one of those things before calling event.respondWith(). This will help your fetch handler play nicely with any other fetch handlers that might also be registered and which, e.g. respond to subresource requests using a caching strategy. Something like the following should work:

    self.addEventListener("fetch", (event) => {
      if (!["document", "iframe", "worker"].includes(event.request.destination)) {
        return;
      }
    
      event.respondWith(/* your logic here */);
    });