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

我有一个JavaScript文件,读取另一个文件,可能包含需要eval()编辑的JavaScript片段。 脚本片段应该符合严格的JavaScript子集,限制了他们可以做什么以及哪些variables可以更改,但是我想知道是否有某种方法可以通过阻止eval在全局范围中看到variables来强制执行此操作。 像下面这样:

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

实际的代码不需要看起来像这样 – 我打开任何和所有怪异的技巧与闭包等,但我想知道这是甚至可能的

简而言之 :不。如果它在全球范围内,任何事情都可以使用。

长的答案 :如果你是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()它(或者将它传递给新的Function() ,或者以任何其他与eval()方式使用它。

你不能限制eval的范围

顺便看到这个职位

可能还有其他方法可以完成你想要在事物的macros伟计划中完成的任务,但是你不能以任何方式限制eval的范围。 您可以隐藏某些variables作为JavaScript中的私有variables,但我不认为这是你要去的。

这是一个想法。 如果你使用了一个静态分析器(例如你可以用esprima构build的东西)来确定被评估的代码使用哪些外部variables,并将它们别名。 通过“外部代码”我的意思是评估代码使用的variables,但不声明 。 这是一个例子:

 eval(safeEval( "var x = window.theX;" +"y = Math.random();" +"eval('window.z = 500;');")) 

其中safeEval返回阻止访问外部variables的上下文修改的javascriptstring:

 ";(function(y, Math, window) {" +"var x = window.theX;" +"y = Math.random();" +"eval(safeEval('window.z = 500;');" "})();" 

现在有几件事情可以做到:

  • 你可以确保被评估的代码不能读取外部variables的值,也不会写入(通过传递undefined的函数参数或不传递参数)。 或者你可以简单地抛出一个exception,以防止variables被不安全地访问。
  • 您还要确保由eval创build的variables不会影响周围的范围
  • 你可以允许eval通过在闭包之外声明这些variables而不是作为函数参数来在周围的范围中创buildvariables
  • 您可以通过复制外部variables的值并将它们用作函数的参数来允许只读访问
  • 您可以通过告诉safeEval不要别名这些特定的名称来允许读写访问特定的variables
  • 您可以检测到eval不修改特定variables的情况,并允许它被自动排除在外(例如,在这种情况下,math不会被修改)
  • 您可以通过传入与周围环境不同的参数值来给eval一个运行环境
  • 您可以通过从函数返回函数参数来捕获上下文更改,以便您可以在eval外部检查它们。

请注意,使用eval是一个特殊情况,因为从本质eval(safeEval(...)) ,它不能被包装在另一个函数中(这就是为什么我们必须做eval(safeEval(...)) )。

当然,做所有这些工作可能会减慢你的代码速度,但是肯定有一些地方不是什么大问题。 希望这有助于某人。 如果有人创造了一个概念的certificate,我很乐意在这里看到一个链接。 )

有一个叫做Google Caja的项目。 你可以使用Caja“沙箱”的第三方JavaScript。 https://developers.google.com/caja/

不要使用eval 。 还有一种替代方法, js.js JS编写的 js.js : JS解释器 ,以便您可以在任何您设置的环境中运行JS程序。 以下是项目页面中的API示例:

 var jsObjs = JSJS.Init(); var rval = JSJS.EvaluateScript(jsObjs.cx, jsObjs.glob, "1 + 1"); var d = JSJS.ValueToNumber(jsObjs.cx, rval); window.alert(d); // 2 JSJS.End(jsObjs); 

没有什么可怕的,你可以看到。

类似于上面的with block方法中的dynamic函数包装脚本,这允许您将伪全局添加到要执行的代码。 您可以通过将具体内容添加到上下文来“隐藏”特定的内容。

 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

不要执行你不信任的代码。 全局将始终可用。 如果你信任代码,你可以在它的作用域中使用特定的variables来执行它,如下所示:

 (new Function("a", "b", "alert(a + b);"))(1, 2); 

这相当于:

 (function (a, b) { alert(a + b); })(1, 2); 

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

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

以下是如何使用它:

 var obj = {key: true}; evalInContext(obj, 'key ? "YES" : "NO"'); 

它会返回"YES"

如果您不确定要执行的代码是expression式还是语句,可以将它们合并:

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