I\'m wondering if it\'s possible to sandbox JavaScript running in the browser to prevent access to features that are normally available to JavaScript code running in an HTML
I think that js.js is worth mentioning here. It's a JavaScript interpreter written in JavaScript.
It's about 200 times slower than native JS, but its nature makes it a perfect sandbox environment. Another drawback is its size – almost 600 kb, which may be acceptable for desktops in some cases, but not for mobile devices.
1) Suppose you have a code to execute:
var sCode = "alert(document)";
Now, suppose you want to execute it in a sandbox:
new Function("window", "with(window){" + sCode + "}")({});
These two lines when executed will fail, because "alert" function is not available from the "sandbox"
2) And now you want to expose a member of window object with your functionality:
new Function("window", "with(window){" + sCode + "}")({
'alert':function(sString){document.title = sString}
});
Indeed you can add quotes escaping and make other polishing, but I guess the idea is clear.
With NISP you'll be able to do sandboxed evaluation. Though the expression you write is not exactly a JS, instead you'll write s-expressions. Ideal for simple DSLs that doesn't demand extensive programming.
All the browser vendors and the HTML5 specification are working towards an actual sandbox property to allow sandboxed iframes -- but it's still limited to iframe granularity.
In general, no degree of regular expressions, etc. can safely sanitise arbitrary user provided JavaScript as it degenerates to the halting problem :-/
You can wrap the user's code in a function that redefines forbidden objects as parameters -- these would then be undefined
when called:
(function (alert) {
alert ("uh oh!"); // User code
}) ();
Of course, clever attackers can get around this by inspecting the Javascript DOM and finding a non-overridden object that contains a reference to the window.
Another idea is scanning the user's code using a tool like jslint. Make sure it's set to have no preset variables (or: only variables you want), and then if any globals are set or accessed do not let the user's script be used. Again, might be vulnerable to walking the DOM -- objects that the user can construct using literals might have implicit references to the window object that could be accessed to escape the sandbox.
As mentioned in other responces, it's enough to jail the code in sandboxed iframe (without sending it to the server-side) and communicate with messages. I would suggest to take a look at a small library I created mostly because of the need to providing some API to the untrusted code, just like as described in the question: there's an opportunity to export the particular set of functions right into the sandbox where the untrusted code runs. And there's also a demo which executes the code submitted by a user in a sandbox:
http://asvd.github.io/jailed/demos/web/console/