Last Updated: February 25, 2016
·
3.44K
· ushis

JavaScript sandbox with Web Workers

In an application i wrote it was necessary to allow the the user to run arbitrary JavaScript (actually CoffeeScript). To prevent that the users code (accidently) interfers with the application code, i looked around for JS sandbox solutions and figured out, that Web Workers are pretty great to isolate code excution.

The flow is pretty straight forward:

  • Init the Web Worker.
  • Wait for the user to enter some code.
  • Send the code to the Web Worker.
  • Eval the code in the Web Worker and send the result back to the app.
  • Reinitialize the Web Worker after every evaluation, to prevent state. Maybe the user was clever enough to override self.postMessage...

The application:

var form = document.getElementById('form'),
  textarea = form.querySelector('textarea'),
  sandbox = null;

function initSandbox() {
  if (sandbox !== null) {
    sandbox.terminate();
  }
  sandbox = new Worker('sandbox.js');

  sandbox.addEventListener('message', function(e) {
    initSandbox();
    alert(e.data.code + ' //=> ' + e.data.result);
  });

  sandbox.addEventListener('error', function(e) {
    initSandbox();
    alert(e.message);
  });
}
initSandbox();

form.addEventListener('submit', function(e) {
  e.preventDefault();
  sandbox.postMessage(textarea.value);  
}); 

The Web Worker is even simpler:

self.addEventListener('message', function(e) {
  self.postMessage({
    code: e.data,
    result: JSON.stringify(eval(e.data))
  });
});

Additionally it is possible to add timeouts to kill the worker, if the user wrote an infinite loop.

Happy sandboxing!

References:

5 Responses
Add your response

over 1 year ago ·

parallel.js looks sweet. thx for he hint.

over 1 year ago ·

Very nice tip @ushis!

over 1 year ago ·

Great tip. Btw, don't need to add even 2KB of third party library. It works like a charm.

over 1 year ago ·

I've got a lib for easy snadboxing (and replace manual messaging with exporting the given functions directly into the sandbox):

https://github.com/asvd/jailed

(Not sure if reinit of a sandbox is necessary upon each evaluation. What about simply masking self and postMessage with local vars as null (before evaluating the code)?

over 1 year ago ·