众所周知,从字符串创建的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代码设置一个完全受控且隔离的环境。有什么风险?
以下是我可以看到的一些问题:
window
,document
或localStorage
或其他任何敏感内容的内容放入env
。 env
,除非您对不受信任的代码进行变更。
with
块内的代码无法访问其外的任何。如果它需要Math
,Object
或String
之类的内容,则必须将其放入env
- 这意味着可以通过恶意代码修改这些内容。甚至上面我最小例子中的eval
函数也可以修改。
只要您遵循这些指导原则,这实际上是否安全?还有其他问题吗?
答案 0 :(得分:1)
很容易摆脱这种环境,通过多种不同的方式,其中一些或全部可能会得到缓解:
对象、数组和 RegExp 文字({ }
、[ ]
和 /.../
)不受代理的阻碍,并允许访问(和更改){{1 }}、Object.protoype
和 Array.prototype
。但是,您可以在运行 RegExp.prototype
之前使用 Object.freeze
锁定这些。
您必须在评估字符串中添加 eval
,否则脚本可以通过将 delete env.eval
函数重命名为 eval
您无法阻止创建可能使用全局 globalEval = eval;
对象:this
的新函数。可能通过将 (function () { this.globalFunc(); })()
附加到您评估的输入来强制执行严格模式可以消除此转义向量。
对 "use strict";
构造函数的任何访问(通过 Function
)都允许执行全局代码。您可以 (a=>a).__proto__.constructor
来阻止这种情况,但可能还有其他方法可以访问 delete Function.constructor
。