As the Wikipedia
article states, the Sandbox is a mechanism for safe execution of programs. Sandboxes are often used to run untested code, untested code from unknown sources, as well as to launch and detect viruses.

Imagine that we have a task: there is a project and users can write their own scripts (widgets, add-ons, plug-ins) under it. We want user scripts to do nothing wrong (theft of cookies is the least that they can do).
The article will discuss the attacks that can be committed by attackers and the methods of safe execution of third-party code.
Let's start with the types of attacks that we have to prevent.
Types of attacks
Next comes a whole bunch of “attack vectors” with examples (the links to the original article), if you are not interested in expanding your horizons, scroll to the end of the post. Attacks are not cross browser.
')
GlobalObjectPoisoning - Poisoning Global Objects
Array.prototype[4] = 'four'; var a1 = []; alert('a1 has length ' + a1.length + ' but element 4 is ' + a1[4]); var a2 = new Array(5); alert('a2 has length ' + a2.length + ' and its element 4 is also ' + a2[4]);
EvalArbitraryCodeExecution - eval and the Function constructor can execute third-party code.
eval('alert("your cookie is " + document.cookie)'); (new Function('alert("your cookie is " + document.cookie)'))();
ArgumentsMaskedByVar - the array of function arguments is masked by var arguments in Opera
(function (a, b, c) { var arguments = [1, 1, 1]; alert('arguments[0] === ' + arguments[0] + ', a=' + a); arguments[0] = 2; alert('arguments[0] === ' + arguments[0] + ', a=' + a); })(0, 0, 0);
CrossScopeParameterModification - the arguments array allows you to change your parameters
(function (a) { arguments[0] = 1; alert('a=' + a); })(0);>
ArgumentsExposesCaller - it is possible to pull the arguments of an external function using caller
function untrusted() { alert('got function ' + untrusted.caller + ' : ' + arguments.callee.caller.arguments[0]); } (function trusted() { untrusted(); })(4);
FunctionMemberCrossScopeParameterAccess - it is possible to replace the arguments of the external function from the internal function
function f(a) { g(); alert(a); } function g() { f.arguments[0] = 1; } f(0)
TypeofInconsistent - typeof bug with regular expressions in webkits
'function' === (typeof /./) 'function' === (typeof alert)
InaccessibleLocalVariables - Local variables may not be available using catch (localVarName)
(function () { var arguments; alert('arguments === undefined: ' + (arguments === undefined)); })(); (function () { var e; try { throw 1; } catch (e) { } alert('arguments === undefined: ' + (arguments === undefined)); })(); (function () { var e = 1; try { throw 2; } catch (e) { } alert('e === 1 : ' + e); })();
CatchBlocksScopeBleed - it is possible to replace global variables using catch
var a = 0; (function () { try { throw 1; } catch (a) { } })(); alert(a); // alerts 1 on old FF (function () { var a = 0; try { throw 1; } catch (a) { } alert(a); // alerts 1 on IE 6 and 7 (IE 8 not tested) })();
GlobalScopeViaThis - It is possible to access the Global scope using this in functions.
(function () { alert('your cookie is ' + this.document.cookie); })(); setTimeout( function () { alert('your cookie is ' + this.document.cookie); }, 0)
DeleteUnmasksGlobals - Hidden global variables in with can be opened using delete
with ({ document: null }) { delete document; alert('your cookie is ' + document.cookie); }
FunctionConstructor - The constructor of a function is accessible through the 'constructor' property.
((function () {}).constructor)( 'alert("document.cookie = " + document.cookie)')()
ObjectEvalArbitraryCodeExecution - Object.eval allows you to execute any code in Firefox.
({}).eval('alert("Your cookie is " + document.cookie)')
ObjectWatch - Object.watch allows you to poison and receive any external data
function untrusted(o) { o.watch( 'private_', function (obj, oldval, newval) { alert('untrusted got oldval ' + oldval + ' and newval ' + newval); return 'poisoned'; // substitute a bogus value }); } // Trusted code var o = { private_: 'old' }; untrusted(o); o.private_ = 'new'; alert('private is now ' + o.private_);
ObjectToSourceLeaksPrivates - Object.toSource and uneval allows you to access private properties
// Untrusted code function untrusted(o) { // untrusted need not attempt to access private_ directly var privateValue = o.toSource().match(/private_:\s*(\d+)/)[1] * 1; alert('private value is ' + privateValue); } var o = { private_: 4 } untrusted(o);
FunctionMethodsLeakGlobalScope - Function.call or Function.apply can open a global object using some of the values ​​of this.
(function () { alert(this === window); }).call(null); (function () { alert(this === window); }).call(undefined); alert(window === ([]).sort.call()); alert(window === ([]).reverse.call()); // Firefox2 only. [https://bugzilla.mozilla.org/show_bug.cgi?id=406337] var o = { valueOf: function () { return null } }; (function () { alert(this === window); }).call(o);
ConditionalCompilationComments - Conditional compilation allows an attacker to hide the code.
StringObfuscationIsEasy - String Obfuscation
(function () { var s = 'cons'; s += 'tructor'; (new ((function () {})[s])('alert("hello")'))(); })();
ParentCircumventsScoping - Using __parent__ it is possible to access variables from any scope
(function () { var alert = null; // boilerplate that masks global alert (function () { // untrusted code that can't access alert directly ({}).__parent__.alert('hello'); })(); })();
JsControlFormatChars - The invert RTL character or [: Cf:] can be used to hide the code in comments.
<html> <body onload=" /‍/.test(''); /* alert('hi'); // */ "> </body> </html>
InconsistentlyReservedKeywords - Context Sensitive Words: const constructor prototype
this['const'] = 0; const alert = f();
ErrorExposesParameterValues - Using the error stack trace, you can access the parameters passed to external functions.
function skroob(luggageCombination) { darkHelmet(); } function darkHelmet() { var combo = Number((new Error).stack.match(/skroob\((\d+)\)/)[1]); alert('Only an idiot would use that combination!: ' + combo); } skroob(1234);
RegexpsLeakMatchGlobally -
Regulars can be run on the last line sent to the last regular expression.
// Privileged code (function () { var queryString = document.location.search; // Assume it's "?password=1234" function params() { return queryString.split(/[&?]/g); } if (params()[0] === 'debug=on') { // ... } })(); // Unprivileged code without direct access to document.location (function () { alert(/.*/.exec()); })();
EvalBreaksClosureEncapsulation - The evel call can break the scope encapsulation in older versions of ff
function counter(i) { return function () { return ++i; }; } var myCounter = counter(0); alert(myCounter());
PostIncrementAndDecrementCanReturnNonNumber -
Post -
increment and post-dekriment may not return a number - a way to get the constructor Function
(function() { var c = 'constructor'; var F = (function(){})[c++];
A whole bunch of attacks, including attacks from html, css
code.google.com/p/google-caja/wiki/AttackVectorsGiven all these attacks, we must provide a certain API, so that the plugin does not work autonomously.
The features we need to provide the plugin
1. Getting access to some user data.
2. Perform some actions on behalf of the user.
How to isolate yourself from the attacker and give a good developer every opportunity ?!
1. Moderation

We can hire a team of moderators who are well versed in the code, plus accepting bug reports from users.
Disadvantages: extremely expensive, and extremely inefficient. Good moderators have to pay a lot, but you can always find a hacker who is more skilled than any moderator, plus the human factor. Users may not find an error, the plugin can do its dirty work unnoticed by the user.
Advantages: no
2. Sandbox in iFrame
This option is used in jsfiddle
1. We take out user scripts to the left domain
2. Forbid to perform alert prompt confirm
3. The user has the right to do anything in his frame
4. API provided by postMessage (asynchronously)
Disadvantages: plugins can attack other plugins if they have a common domain. Asynchronous exchange. There may be other functions besides alert prompt confirm, which may interfere with the user. not all browsers support postMessage
Advantages: simple implementation of sendboxing
More about it: dean.edwards.name/weblog/2006/11/sandbox3. Sandbox in WebWorkers
Workers are excellent sandwiches, they are already limited to the browser environment.
1. API provides by postMessage (asynchronously)
2. We must create a library of interface elements.
3. Items will respond to events asynchronously.
Disadvantages: the developer of the plugin is limited to interface components. Asynchronous exchange and events. Not all browsers support WebWorkers.
Advantages: simple implementation of sendboxing
Example: github.com/eligrey/jsandbox4. Static analysis and translation of code into code
We analyze the source code, replace potentially dangerous configurations with safe ones (css javascript html), or do not miss potentially dangerous ones.
Disadvantages: no output, we get no source code
Pluses: works everywhere
4.1. Douglas Crockford's ADsafe

ADsafe defines a subset of JavaScript that is powerful enough to allow guest code to perform important actions, while preventing scripts from damaging or invading source code.
ADsafe removes features from JavaScript that either do not secure or give unchecked access to browser components. Their list includes: global variables, this, arguments, eval, with, arguments, callee, caller, constructor, eval, prototype, stack, unwatch, valueOf, watch, names ending with or beginning with _, operator [], Date and Math .random
Restrictions: Before starting the code, you need to process JSLint, the code must be in UTF-8, html id must be unique
Disadvantages: excessive developer restrictions
Pluses: works everywhere
More details can be found here: www.adsafe.orgPlay with adsafe here: www.jslint.com (enable ADsafe flag)
4.2. Google caja

Unlike ADsafe, Google Caja translates (using the “cajoler” compiler) JavaScript, HTML, CSS code to secure (cajoled) JavaScript, HTML, CSS code. Cajoler conducts static analysis to identify potentially dangerous moments where static analysis is impossible to check dynamically - in the process. In addition, cajoler does virtualization of DOM pieces using virtual iframes. Caja protects against all types of attacks described
here .
Disadvantages: we get the modified code
Advantages: works everywhere, does not impose unnecessary restrictions on the developer
Code translation examplesBefore
<script> alert(document.cookie); top.location = "http://www.thinkfu.com/evil.gif"; </script>
After
<script> { ___.loadModule({ 'instantiate': function (___, IMPORTS___) { return ___.prepareModule({ 'instantiate': function (___, IMPORTS___) { var dis___ = IMPORTS___; var moduleResult___, x0___, x1___; moduleResult___ = ___.NO_RESULT; try { { (IMPORTS___.alert_v___ ? IMPORTS___.alert : ___.ri(IMPORTS___, 'alert')).i___((x0___ = IMPORTS___.document_v___ ? IMPORTS___.document : ___.ri(IMPORTS___, 'document'), x0___.cookie_v___ ? x0___.cookie : x0___.v___('cookie'))); moduleResult___ = (x1___ = IMPORTS___.top_v___ ? IMPORTS___.top : ___.ri(IMPORTS___, 'top'), x1___.location_w___ === x1___ ? (x1___.location = 'http://www.thinkfu.com/evil.gif') : x1___.w___('location', 'http://www.thinkfu.com/evil.gif')); } } catch (ex___) { ___.getNewModuleHandler().handleUncaughtException(ex___, IMPORTS___.onerror_v___ ? IMPORTS___.onerror : ___.ri(IMPORTS___, 'onerror'), 'unknown', '2'); } return moduleResult___; }, 'cajolerName': 'com.google.caja', 'cajolerVersion': '4427', 'cajoledDate': 1302010087717 }).instantiate___(___, IMPORTS___), ___.prepareModule({ 'instantiate': function (___, IMPORTS___) { var dis___ = IMPORTS___; var moduleResult___; moduleResult___ = ___.NO_RESULT; { IMPORTS___.htmlEmitter___.signalLoaded(); } return moduleResult___; }, 'cajolerName': 'com.google.caja', 'cajolerVersion': '4427', 'cajoledDate': 1302010087733 }).instantiate___(___, IMPORTS___); }, 'cajolerName': 'com.google.caja', 'cajolerVersion': '4427', 'cajoledDate': 1302010087748 }); } </script>
Script alert "Untrusted gadget says: undefined" and not redirects
As you can see, the source code is far from being obtained, but the end user is protected from intruder attacks.
Project Page: code.google.com/p/google-cajaTwist Google Caja here :
caja.appspot.comI would like to hear what methods of sandboxing you use, do you have examples of implementation?
Criticism, questions and suggestions are welcome!
PS I apologize for the breakthrough kata - the parser overslept