Last Updated: February 25, 2016
·
4.46K
· 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 ·

Have a fresh tip? Share with Coderwall community!

Post
Post a tip
Did you know?

JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.

Security insights from Cside