JavaScript - 如何从eval'd脚本隐藏全局范围

kol*_*kol 6 javascript information-hiding eval global-variables

我通常认为全局范围是一个总是可以从任何地方访问的命名空间.我想知道理论上是否有可能完全隐藏全球范围.例如,假设我们有一些我们想要的代码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);
Run Code Online (Sandbox Code Playgroud)

通过包装eval调用,thiswindow可以从隐藏code:

(function (window) { eval(code); }).call({});
Run Code Online (Sandbox Code Playgroud)

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

小智 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.
Run Code Online (Sandbox Code Playgroud)

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

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

我认为有一些黑客可能会解决这个问题,但这应该涵盖大多数情况.


jon*_*o45 5

注意:这仍然是一项正在进行中的工作,部分受到了眯眼的代码片段的启发。

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
    };
}
Run Code Online (Sandbox Code Playgroud)

输出结果(来自 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
*/
Run Code Online (Sandbox Code Playgroud)

和一些结果的jsfiddle

注意:一些意外的结果出现在 fiddle 中,但没有出现在其他工具中(即,location当从 firefox aurora 查看 fiddle 时,变量返回页面的 url,但不是在 chrome 上,也不是在 Scratchpad devtool 上——可能是 Firefox__noSuchMethod__或类似工具的手工作品“后期绑定”机制,导致仅在访问时添加属性)。