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:
Written by ushi
Related protips
5 Responses
Checkout this lib http://adambom.github.io/parallel.js/ :)
parallel.js looks sweet. thx for he hint.
Very nice tip @ushis!
Great tip. Btw, don't need to add even 2KB of third party library. It works like a charm.
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)?