Search code examples
javascriptamazon-web-servicessecurityamazon-s3web-worker

JS Web workers and security


I want to use a dedicated web worker (not a shared worker) to load files from S3 in the background after users login. To gain access to the s3 files, I need to authenticate the user (AWS Cognito).

I tried calling the web worker from the browsers' js like this, after creating an authenticated s3 object.

    async function softSyncPlaground(oFoldersInSync, localS3Object){
        var worker = new Worker('js/worker_syncPlayground.js');
         worker.addEventListener('message', function(e) {
            console.log('Worker said: ', e.data);
        }, false);
        worker.postMessage([oFoldersInSync, localS3Object]);
    } 

But it won't work as one can't submit an object with functions into a web worker.

So my fallback is to post the credentials into the web worker and generate the authenticated s3 object there.

    async function softSyncPlaground(oFoldersInSync, sIdentityPoolId, oLogins){
        var worker = new Worker('js/worker_syncPlayground.js');
         worker.addEventListener('message', function(e) {
            console.log('Worker said: ', e.data);
        }, false);
        worker.postMessage([oFoldersInSync, sIdentityPoolId, oLogins]);
    }

However, sending credentials around makes me feel uneasy in terms of security.

  • Can "worker.postMessage()" be intercepted?
  • If I want switch to a shared worker, later on (I've a "nice to have" use case for this), would this affect security?

Any thoughts on this topic?


Solution

  • Can "worker.postMessage()" be intercepted?

    Yes, just like pretty much everything in JS, but only from the client-side itself.

    For instance, one could simply overwrite the Worker's prototype's method and your instance would get affected:

    const worker = new Worker( "data:text/javascript," );
    worker.postMessage( "my-super-secret-password" );
    <script id="evil-script">
    Worker.prototype.postMessage = (...args) => {
      console.log("caught", ...args);
    };
    </script>

    But if a malicious script is able to do that, it is also able to overwrite the methods you used to get that password in the first place (e.g Response.prototype.json or XMLHttpRequest.prototype.response).
    So there is no "added" risk here.

    If I want switch to a shared worker, later on (I've a "nice to have" use case for this), would this affect security?

    Not if you don't make it more dangerous yourself.

    The "clients" of a SharedWorker (SW) can only send a MessagePort to the SW, they can't access its global scope and can't read anything from it.
    So as long as you don't postMessage() the sensitive information from the SW to the clients yourself, you are safe. Note that since Workers can only be created from same-origin, all clients can actually read its source, but anyway sensitive information should never be hard-coded in JS sources.

    [gathered from the comments]
    I was worried, as an HTTP Call or a WebSocket would be easier to eavesdrop.

    No worries here, the MessagePort interface is 100% client-side. Once again, yes a compromised machine could have a malicious script read directly in its RAM and derive the sensitive information from there, but once again, if they can do it... they can certainly access that token by means a lot simpler.