使用 ES6 `Proxy` 和 `with` 真的安全吗?

Jos*_*osh 6 javascript security eval

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

然而,我想知道 ES6 代理是否会改变这一点。考虑:

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

代理对象假装拥有所有可能的属性,这意味着它会阻止更高范围的搜索。在该with块内,任何未在 上设置的属性env都会出现undefined,而在 with 块内设置的任何全局属性实际上都会在 上设置env

这似乎让我可以为ed代码运行建立一个完全受控和隔离的环境eval。有什么风险?

以下是我看到的一些担忧:

  1. 不要将任何引用window、或document、或localStorage或任何其他敏感内容放入 中env
  2. 不要放入任何可变对象,env除非您同意不受信任的代码改变它。
    • 解决方案:如有必要,进行深复制。
  3. 块内的代码with无法访问块外的任何内容。如果需要诸如MathObject、 或 之类的东西String,则必须将它们放入env- 这意味着这些可以被恶意代码修改。即使是eval上面我的最小示例中的函数也可以修改。
    • 解决方案:为这些对象创建代理,将对特定属性的只读访问权限列入白名单。

只要遵循这些准则,这真的安全吗?还有其他问题吗?

aps*_*ers 3

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

  1. 对象、数组和 RegExp 文字({ }[ ]/.../)不受代理的阻碍,并允许访问(和变化)Object.protoypeArray.prototypeRegExp.prototype。但是,您可以Object.freeze在运行eval.

  2. 您必须delete env.eval在评估的字符串内,否则脚本可以通过重命名函数来执行全局代码,eval例如globalEval = eval;

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

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