15

Would it be possible to sandbox user-submitted Javascript by overriding various functions such as alert, window.location, and eval?

I'm not looking for a perfect solution. I'm sure some people would still find a way to rearrange divs to spell out swear words or something malicious, but if I could disable page redirects 100% reliably I would be mostly happy.

I tried in Chrome, and doing something like

context={}; //use this to prevent `this` from being `window`
context.f=function(){
  var window=null,location=null,eval=function(){};
  console.log(window); //also the other two
};
context.f();

seems promising. If I replace the console line with user-submitted code (checking for paren balancing), would that be an absurdly bad idea or a mildly bad idea? On Chrome I can still break things by going through this to Function and redefining things, but that would be acceptable to me.

Loyal Tingley
  • 910
  • 1
  • 8
  • 20
  • Use an iframe. Otherwise make sure to get rid of `setTimeout` and `setInterval` as the first param can be a string, which will be `eval`'d. – Ivo Wetzel Feb 18 '11 at 17:40
  • 2
    Then also don't forget to hide the (prototypes of) `Object`, `Number`, especially `Function`, and basically all the properties of the global object (`window`). If you 'isolate' the user scripts in an IFrame, make sure they can't access the frames collection in any way. – Martijn Feb 18 '11 at 19:47
  • @Martijn is it possible to hide the prototypes? Couldn't they just access them from `(function(){}).constructor` or similar anyway? – Loyal Tingley Feb 20 '11 at 04:54
  • Related: http://stackoverflow.com/questions/2986908/javascript-sandbox – Ates Goral Jan 27 '12 at 19:20

8 Answers8

11

You can use Microsoft Web Sandbox or Google Caja.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 6
    can we break Microsoft by dumping bad code into their sandbox? It must leak somewhere. – Raynos Feb 18 '11 at 18:06
  • 1
    These both use a server-side translator, right? I'd like to do it on the client-side if possible. This is more of a "can it be done" question than "I need a solution" question. – Loyal Tingley Feb 20 '11 at 05:03
  • @Loyal: If it can be done on the server, it can also be done on the client. – SLaks Feb 20 '11 at 12:01
4

Here are two more possible solutions (disclaimer: I just started looking for this myself, so I am not an expert).

This is very interesting, uses web workers to sandbox untrusted code:

https://github.com/eligrey/jsandbox

even though, I wonder if that is maintaned anymore, or if the following html5 "sandbox" iframe attribute supersedes it:

http://www.w3schools.com/html5/att_iframe_sandbox.asp

vincenzoml
  • 413
  • 1
  • 3
  • 10
  • JSandbox is no longer maintained. [Source](https://github.com/eligrey/jsandbox/issues/8#issuecomment-50379022) – Joncom Jul 28 '14 at 19:20
3

vm.js is a javascript virtual machine implemented in pure coffeescript(should run in relatively old browsers) and can be used as a lightweight in-process sandbox. It can break infinite loops and shields global objects from modifications.

Thiago Padilha
  • 4,590
  • 5
  • 44
  • 69
2

Masking the globals with local variables is not secure actually. Preprocessing the untrusted code with tools like Google Caja may help, but it's not necessary:

  • For a web-browser simply running a code in a Worker is enough - it seems to be pretty restricted nowadays. See update below

  • For Node.js you may fork() in a sandboxed process and execute the code there (using the child_process module).

There are also some libraries for simplifying the sandboxing, one of those created by myself is Jailed (there's also a demo with JS-Console which executes user-submitted code in a sandbox).

Update: obviously I was wrong, the worker is not secure by itself, as it can access some of same-origin stuff, like IndexedDB for instance. I have submitted a related question. The solution is to additionally put the worker into a sasndboxed iframe, which is also implemented in my Jailed library.

Community
  • 1
  • 1
asvd
  • 944
  • 10
  • 16
2

Depending on what this needs to do, you could always run the javascript in a document-context-free environment, like through Rhino, and then grab the results server-side and clean/insert those.

Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
  • That could be done using AJAX and any server-side JS engine (Rhino, SpiderMonkey, [MSScriptControl](http://www.microsoft.com/downloads/en/details.aspx?FamilyID=d7e31492-2595-49e6-8c02-1426fec693ac), [seed](http://live.gnome.org/Seed), [node.js](http://nodejs.org), [JSDB](http://www.jsdb.org), [EmbedThis EJScript](http://www.ejscript.org)). It all depends on your server-side technology. – Martijn Feb 18 '11 at 19:55
  • I'd like to run it client-side, although this might be an option. Thanks :) – Loyal Tingley Feb 20 '11 at 04:59
2

You could also try Douglas Crockford's AdSafe, though it does limit the possibilities of JavaScript.

Martijn
  • 13,225
  • 3
  • 48
  • 58
1

Use HTML5 "sandbox" iframe attribute.

Denis Gorbachev
  • 507
  • 4
  • 12
1

I made a javascript function for this.

function evalUnsafe(userCode) {
  var vars = [];

  var legal = {console: 'console', alert: 'alert'};
  for(var b in this) {
    if (!(b in legal)) {
      vars.push(b);
    }
  }

  var funcs = vars.join(",");
  var code = "(function sandbox(" + funcs + ") {function runthis() {eval(" + JSON.stringify(userCode) + ");};var a = new runthis();})();";
  eval(code);
}

And then you can do this

Example 1:

evalUnsafe("alert(window);");

Example 2 (from a php file):

evalUnsafe(<?php echo json_encode(file_get_contents("example.js"));?>);

You can download it from here:

https://github.com/oyvindrestad/javascriptsandbox