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.

4
  • 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. Commented Feb 18, 2011 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. Commented Feb 18, 2011 at 19:47
  • @Martijn is it possible to hide the prototypes? Couldn't they just access them from (function(){}).constructor or similar anyway? Commented Feb 20, 2011 at 4:54
  • Related: stackoverflow.com/questions/2986908/javascript-sandbox Commented Jan 27, 2012 at 19:20

9 Answers 9

11

You can use Microsoft Web Sandbox or Google Caja.

Sign up to request clarification or add additional context in comments.

3 Comments

can we break Microsoft by dumping bad code into their sandbox? It must leak somewhere.
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: If it can be done on the server, it can also be done on the client.
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

1 Comment

JSandbox is no longer maintained. Source
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.

Comments

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.

2 Comments

That could be done using AJAX and any server-side JS engine (Rhino, SpiderMonkey, MSScriptControl, seed, node.js, JSDB, EmbedThis EJScript). It all depends on your server-side technology.
I'd like to run it client-side, although this might be an option. Thanks :)
2

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

Comments

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.

Comments

1

Use HTML5 "sandbox" iframe attribute.

Comments

0

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

1 Comment

This is a terrible solution that a) doesn't work on a page using frames (with syntax errors from variables named 0 etc) and b) can trivially be broken out of, e.g. with evalUnsafe('globalThis')
-1

JS-Interpreter (github) is a way to sandbox your js code by creating "its own virtual machine with no external APIs except as provided by the developer". It is based on Acorn by Marijn Haverbeke. This solution is quite slow however (200x according to the docs).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.