Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript - How to hide global scope from eval'd script

I usually think of global scope as a namespace that always can be accessed from everywhere. I would like to know whether it is theoretically possible to completely hide global scope. For example, assume we have some code we would like to evaluate (in the console of a browser):

var code = 
  "console.log(this);   " + // access the global object directly
  "console.log(window); " + // access the global object as the window object
  "newGlobalVar = 42;   ";  // implicitly create global object
eval(code);

By wrapping the eval call, this and window can be hidden from code:

(function (window) { eval(code); }).call({});

But I can't stop the code implicitly create global variables. Is it possible somehow? I don't want to use this stuff, I'm just curious.

like image 864
kol Avatar asked May 29 '13 20:05

kol


People also ask

Why should we avoid global variables in JavaScript?

Avoid global variables or minimize the usage of global variables in JavaScript. This is because global variables are easily overwritten by other scripts. Global Variables are not bad and not even a security concern, but it shouldn't overwrite values of another variable.

Is VAR globally scoped?

The var statement declares a function-scoped or globally-scoped variable, optionally initializing it to a value.

Can we create restricted scope variable in JavaScript?

You can't restrict the scope of a Function using the "call" or "apply" methods, but you can use a simple trick using "eval" and scoping to essentially hide any specific global variables from the function to be called.


3 Answers

If you're running in fairly modern browsers, you can mostly block window access by making a function that shadows the window and self variables with parameters, and runs the code in strict mode.

var obj = {};

var func = new Function("self", "window", "'use strict';" + code);

func.call(obj, obj, obj);

console.log(obj); // see if there were any attempts to set global variables.

Any attempt to access window or self will merely access our obj object, and the value of this will also be our obj.

Because we're in strict mode, implicit globals aren't allowed. Also, the default this value of functions will be undefined instead of window.

I think there are a couple hacks that may get around this, but this should cover most scenarios.

like image 132
user1106925 Avatar answered Oct 16 '22 22:10

user1106925


Note: This is still a work in progress and partly inspired by squint's code snippet.

function quarantinedFunction(fnText){
    var exceptionKeys=[
        "eval","Object",  //need exceptions for this else error. (ie, 'Exception: redefining eval is deprecated')
        "Number","String","Boolean","RegExp","JSON","Date",
    ];
    var forbiddenKeys=[
        "fn","fnText","forbiddenKeys","exceptionKeys","empty","oForbiddenKeys",
    ];
    var oForbiddenKeys=Object.create(null);
    var empty=Object.create(null);
    Object.freeze(empty);
    forbiddenKeys.forEach(function(key){
        oForbiddenKeys[key]=null;
    });
    [this,self].forEach(function(obj){
        Object.getOwnPropertyNames(obj).forEach(function(key){
            if(!key.match(/^[\$\w]+$/))return;
            oForbiddenKeys[key]=null;
        });
    });
    exceptionKeys.forEach(function(key){
        delete oForbiddenKeys[key];
    });

    if(0){//debugging.
        return function(){
            return Object.keys(oForbiddenKeys);
            return Object.keys(empty);
        };
    }

    fnText=[
        '"use strict";',
        "var "+Object.keys(oForbiddenKeys).join(", ")+";",
        "{",
        fnText,
        "}"
    ].join("\n");

    var fn= (function(){
        with(empty)
        {
            return new Function("self","window",fnText);
        }
    })();

    return function(){
       return fn.call(Object.create(null));      //self,window undefined
       return fn.call(empty,empty,empty);  //self,window are objects w/o properties
    };
}

Output results (from Firefox scratchpad):

quarantinedFunction("return location.href;")();
/*
Exception: location is undefined
*/
quarantinedFunction("someGlobalVar=15;")();
/*
Exception: assignment to undeclared variable someGlobalVar
*/
quarantinedFunction("return 9*9;")();
/*
81
*/
quarantinedFunction("return console;")();
/*
undefined
*/

And a jsfiddle with some results.

Note: Some unexpected results show up in the fiddle but not in other tools (i.e. the location variable returns the page's url when the fiddle is viewed from firefox aurora, but not on chrome nor on the scratchpad devtool -- possibly the handiwork of Firefox's __noSuchMethod__ or similar 'late-binding' mechanism, resulting in properties being added only when accessed).

like image 44
jongo45 Avatar answered Oct 16 '22 22:10

jongo45


You can just append on beggning: "var window = null" in your eval string. As well, for each property, do a for loop appending to your string in start: for(var p in window) yourEvalString += "var "+p+"=null;"; and put this on a separated scope.

sorry, english ins't my first language, and i'm new logged in Stack Overflow.

like image 1
Erick Santos de Oliveira Avatar answered Oct 16 '22 22:10

Erick Santos de Oliveira