8

我通常认为全局范围是一个始终可以从任何地方访问的命名空间。我想知道理论上是否可以完全隐藏全局范围。例如,假设我们有一些我们想要查看的代码eval(在浏览器的控制台中):

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);

通过包装eval调用,this并且window可以隐藏code

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

但我无法阻止code隐式创建全局变量。有可能吗?我不想用这个东西,我只是好奇。

4

3 回答 3

6

如果您在相当现代的浏览器中运行,您可以通过创建一个使用参数隐藏和变量window的函数来阻止访问,并在严格模式下运行代码。windowself

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.

任何访问windowself将仅访问我们的obj对象的尝试,其值this也将是我们的obj.

因为我们处于严格模式,所以不允许使用隐式全局变量。此外,函数的默认this值将undefined代替window.

我认为有一些技巧可以解决这个问题,但这应该涵盖大多数情况。

于 2013-05-29T21:12:13.740 回答
5

注意:这仍在进行中,部分灵感来自 squint 的代码片段。

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
    };
}

输出结果(来自 Firefox 暂存器):

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
*/

还有一个有一些结果的jsfiddle 。

注意:一些意想不到的结果出现在小提琴中,但没有出现在其他工具中(即location当从 Firefox 极光查看小提琴时,变量返回页面的 url,但不是在 chrome 或暂存器 devtool 上 - 可能是 Firefox__noSuchMethod__或类似工具的手工“后期绑定”机制,导致仅在访问时添加属性)。

于 2013-05-30T00:57:07.133 回答
1

您可以在 eval 字符串中附加 beggning: "var window = null" 。同样,对于每个属性,在 start 中执行一个附加到字符串的 for 循环: for(var p in window) yourEvalString += "var "+p+"=null;"; 并将其放在单独的范围内。

抱歉,英语不是我的第一语言,而且我是新登录 Stack Overflow。

于 2021-10-06T01:15:00.103 回答