Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Semi-sandboxing Javascript eval

Background: I'm working on a framework/library to be used for a specific site in coordination with greasemonkey/userscripts. This framework/library will allow for addon support. The way it will work is an addon registers with the library listing required pages, resources, ectera and the library will wait until all critera is met to call the addon's load() function.

The Issue:In this listing of 'required stuff' I want addon devs to be able to specify javascript(as string) to be evaluated as a 'required resource'. For example 'document.getElementById("banana")'. What I want to do is semi-sandbox the evaluation of 'required resource' so the evaluation can access the window & DOM objects but is not able to directly alter them. I'd also like to make eval, and evalJS inaccessible from the sandbox.


Examples:

  • document.getElementById("banana") -> valid
  • document.getElementById("apple).id = "orange" -> invalid
  • window.grape -> valid
  • window.grape = 'potato' -> invalid
  • (someObj.applesCount > 0 ? 'some' : 'none') -> valid


What I have so far:

function safeEval(input) {

    // Remove eval and evalJS from the window:
    var e = [window.eval, window.evalJS], a;
    window.eval = function(){};
    window.evalJS = function(){};

    try {

        /* More sanition needed before being passed to eval */

        // Eval the input, stuffed into an annonomous function
        // so the code to be evalued can not access the stored
        // eval functions:
        a = (e[0])("(function(){return "+input+"}())");
    } catch(ex){}

    // Return eval and evalJS to the window:
    window.eval = e[0];
    window.evalJS = e[1];

    // Return the eval'd result
    return a;
}


Notes:
This is a Greasemonkey/userscript. I do not have direct access to alter the site, or it's javascript.
The input for safeEval() can be any valid javascript, be it a DOM query, or simple evaluations so long as it does not alter the window object or DOM.

like image 357
SReject Avatar asked Sep 08 '12 21:09

SReject


People also ask

What is JavaScript sandboxing?

Sandboxed JavaScript is a simplified subset of the JavaScript language that provides a safe way to execute arbitrary JavaScript logic from Google Tag Manager's custom templates. To provide a safe execution environment, some features of JavaScript are restricted or removed.

Is eval bad practice JavaScript?

It is a common knowledge that in JavaScript, eval is something that is a bad practice.

Why we should not use eval in JavaScript?

eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension.

What is the alternative of eval in JavaScript?

An alternative to eval is Function() . Just like eval() , Function() takes some expression as a string for execution, except, rather than outputting the result directly, it returns an anonymous function to you that you can call.


1 Answers

There's no absolute way to prevent an end user or addon developer from executing specific code in JavaScript. That's why security measures in an open source language like JavaScript is said to be foolproof (as in it's only effective against fools).

That being said however let's build a sandbox security layer to prevent inexperienced developers from breaking your site. Personally I prefer using the Function constructor over eval to execute user code for the following reasons:

  1. The code is wrapped in an anonymous function. Hence it may be stored in a variable and called as many times as needed.
  2. The function always exists in the global scope. Hence it doesn't have access to the local variables in the block which created the function.
  3. The function may be passed arbitrary named parameters. Hence you may exploit this feature to pass or import modules required by the user code (e.g. jQuery).
  4. Most importantly you may set a custom this pointer and create local variables named window and document to prevent access to the global scope and the DOM. This allows you to create your own version of the DOM and pass it to the user code.

Note however that even this pattern has disadvantages. Most importantly it may only prevent direct access to the global scope. User code may still create global variables by simply declaring variables without var, and malicious code may use hacks like creating a function and using it's this pointer to access the global scope (the default behavior of JavaScript).

So let's look at some code: http://jsfiddle.net/C3Kw7/

like image 86
Aadit M Shah Avatar answered Sep 28 '22 11:09

Aadit M Shah