使用ES6`Proxy`和`with`真正安全`eval`?

时间:2017-06-21 02:43:55

标签: javascript security eval

众所周知,从字符串创建的Javascript eval关键字和Function对象都不应该出于任何原因用于运行不受信任的代码。

但是,我想知道ES6代理是否会改变它。考虑:

let env = {eval: eval};
let proxy = new Proxy(env, { has: () => true });
with(proxy) {eval('...')}

代理对象假装拥有所有可能的属性,这意味着它阻止了对更高范围的搜索。在with块中,未在env上设置的任何属性显示为undefined,并且在with块内设置的所有全局属性实际上都设置在env上。

这似乎允许我为eval ed代码设置一个完全受控且隔离的环境。有什么风险?

以下是我可以看到的一些问题:

  1. 请勿将引用windowdocumentlocalStorage或其他任何敏感内容的内容放入env
  2. 不要将任何可变对象放入env,除非您对不受信任的代码进行变更。
    • 解决方案:必要时制作深层副本。
  3. with块内的代码无法访问其外的任何。如果它需要MathObjectString之类的内容,则必须将其放入env - 这意味着可以通过恶意代码修改这些内容。甚至上面我最小例子中的eval函数也可以修改。
    • 解决方案:为这些对象创建代理,以白名单对特定属性进行只读访问。
  4. 只要您遵循这些指导原则,这实际上是否安全?还有其他问题吗?

1 个答案:

答案 0 :(得分:1)

很容易摆脱这种环境,通过多种不同的方式,其中一些或全部可能会得到缓解:

  1. 对象、数组和 RegExp 文字({ }[ ]/.../)不受代理的阻碍,并允许访问(和更改){{1 }}、Object.protoypeArray.prototype。但是,您可以在运行 RegExp.prototype 之前使用 Object.freeze 锁定这些。

  2. 您必须在评估字符串中添加 eval,否则脚本可以通过将 delete env.eval 函数重命名为 eval

    来执行全局代码
  3. 您无法阻止创建可能使用全局 globalEval = eval; 对象:this 的新函数。可能通过将 (function () { this.globalFunc(); })() 附加到您评估的输入来强制执行严格模式可以消除此转义向量。

  4. "use strict"; 构造函数的任何访问(通过 Function)都允许执行全局代码。您可以 (a=>a).__proto__.constructor 来阻止这种情况,但可能还有其他方法可以访问 delete Function.constructor