将 eval() 限制在一个狭窄的范围内

IT技术 javascript eval
2021-02-02 19:42:30

我有一个 javascript 文件,它读取另一个文件,该文件可能包含需要 eval()-ed 的 javascript 片段。脚本片段应该符合严格的 javascript 子集,该子集限制了它们可以做什么以及可以更改哪些变量,但我想知道是否有某种方法可以通过防止 eval 看到全局范围内的变量来强制执行此操作. 类似于以下内容:

function safeEval( fragment )
{
    var localVariable = g_Variable;

    {
        // do magic scoping here so that the eval fragment can see localVariable
        // but not g_Variable or anything else outside function scope

        eval( fragment );
    }
}

实际代码不需要看起来像这样——我对任何和所有关于闭包等的奇怪技巧持开放态度。但我确实想知道这是否可能

6个回答

简短回答:不。如果它在全局范围内,则可用于任何东西。

长答案:如果您正在eval()编写真正想要阅读或弄乱您的执行环境的不受信任的代码,那么您就完蛋了。但是,如果您拥有并信任所有正在执行的代码,包括正在执行的代码eval(),您可以通过覆盖执行上下文来伪造它:

function maskedEval(scr)
{
    // set up an object to serve as the context for the code
    // being evaluated. 
    var mask = {};
    // mask global properties 
    for (p in this)
        mask[p] = undefined;

    // execute script in private context
    (new Function( "with(this) { " + scr + "}")).call(mask);
}

再次强调:

这只会将受信任的代码与执行它的上下文隔离开来。如果您不信任该代码,请不要使用eval()它(或将其传递给 new Function(),或以任何其他类似 的方式使用它eval())。

这种with方法有一个小问题,以前曾让我感到厌烦在 with 块中声明的函数无权访问 with 语句的目标。
2021-03-21 19:42:30
我检查表达式是否包含 = 并且如果下一个字符不是 = 将阻止它:DI 必须检查更多表达式,但我不知道还可以尝试哪个......我想得到一些错误表达式的例子
2021-03-22 19:42:30
你能举个例子,这怎么会结束?我确实检查了一些但没有找到一些......我会阻止像 var test = 1 这样的变量定义
2021-03-24 19:42:30
我能想到的最简单的坏表达是: (function() { this.document.anythingYouWant... }).call(null); 当使用没有“this”参数的 call 时,“this”成为全局上下文。
2021-03-25 19:42:30
阅读最后的警告,@meph - 不要提供任何你没有写/控制的东西。
2021-03-26 19:42:30

Shog9♦ 的回答很棒。但是如果你的代码只是一个表达式,代码将被执行并且不会返回任何内容。对于表达式,使用

function evalInContext(context, js) {

  return eval('with(context) { ' + js + ' }');

}

以下是如何使用它:

var obj = {key: true};

evalInContext(obj, 'key ? "YES" : "NO"');

它将返回"YES"

如果不确定要执行的代码是表达式还是语句,可以将它们组合起来:

function evalInContext(context, js) {

  var value;

  try {
    // for expressions
    value = eval('with(context) { ' + js + ' }');
  } catch (e) {
    if (e instanceof SyntaxError) {
      try {
        // for statements
        value = (new Function('with(this) { ' + js + ' }')).call(context);
      } catch (e) {}
    }
  }

  return value;
}
哇,这真是令人印象深刻。
2021-04-13 19:42:30

类似于with上面块方法中的动态函数包装脚本,这允许您向要执行的代码添加伪全局变量。您可以通过将特定事物添加到上下文中来“隐藏”它们。

function evalInContext(source, context) {
    source = '(function(' + Object.keys(context).join(', ') + ') {' + source + '})';

    var compiled = eval(source);

    return compiled.apply(context, values());

    // you likely don't need this - use underscore, jQuery, etc
    function values() {
        var result = [];
        for (var property in context)
            if (context.hasOwnProperty(property))
                result.push(context[property]);
        return result;
    }
}

有关示例,请参见http://jsfiddle.net/PRh8t/请注意,Object.keys并非所有浏览器都支持。

你不能限制 eval 的范围

btw 看到这个帖子

可能有一些其他方法可以完成您想要在宏伟计划中完成的任务,但您不能以任何方式限制 eval 的范围。您可以在 javascript 中将某些变量隐藏为伪私有变量,但我认为这不是您想要的。

有一个名为 Google Caja 的项目。您可以使用 Caja 对第三方 javascript 进行“沙盒处理”。https://developers.google.com/caja/