我想创建一个 HTML+JS 环境,用户可以在其中输入和运行任意 JavaScript 代码,这些代码将在给定 jail 对象的上下文中执行。我设置了一个 playground to illustrate what I have so far .
这个做得还不错:
- 基本评估工作:
- 输入:
2 + 2
- 输出:
4
- 输入:
this
返回 jail 对象- 输入:
this
- 输出:
[对象对象]
- 输入:
this.hello()
运行预期的方法- 输入:
this.hello()
- 输出:
hello world!
- 输入:
- 用户可以设置自己的功能并稍后执行:
- 输入:
this.foo = function() { return 42; }
- 输出:
function () { return 42; }
- 输入:
this.foo()
- 输出:
42
- 输入:
- 尝试访问一些我想在 jail 上下文中保持“隐藏”状态的对象失败:
- 输入:
隐藏
- 输出:
ReferenceError: hidden is not defined
- 输入:
但是,它完全无法隐藏全局可访问的属性,例如用户的 window
或 document
:
- 输入:
窗口
- 当前输出:
[对象窗口]
- 期望的输出:
ReferenceError: window is not defined
到目前为止,我想到的最好的解决方案是在 Jail 对象声明中用 undefined
或 null
填充我能想到的所有全局变量, 作为 illustrated in updated version .通过这种方式,它们似乎永远丢失在 jail 范围内,用户将无法访问它们。我的问题:
- 我说得对吗?这样够安全吗?
- 有没有更好的方法,即真正取消定义特定范围内的全局内容,而不是用一些占位符值重写它们?
最佳答案
如果是客户端并且你可以保证使用现代浏览器,请使用 web workers反而;它们更安全,您还可以阻止无限循环占用主线程,并通过调用 Worker#terminate
实现超时。
为每次执行启动一个新的worker:
var worker = new Worker('path/to/evaluator.js');
从工作人员那里接收消息:
worker.onmessage = function (e) {
console.log(e.data);
};
发送代码执行:
worker.postMessage(someCode);
在 worker 中,听:
onmessage = function (e) {
postMessage(eval(e.data));
};
并确保在收到消息后也调用 terminate
,因为 worker 可以调用 postMessage
本身。 (你可以阻止它,但实际上没有意义。)
Web worker 无法访问主执行上下文中的任何内容,它们在另一个线程上运行,并且由浏览器实现,因此它们比典型的 delete-dangerous-things 沙箱安全得多。
但是,他们确实可以访问XMLHttpRequest
;见Is It Possible to Sandbox JavaScript Running In the Browser?如果这是一个问题,请使用其他方法。
关于JavaScript 沙盒 : hide global variables from a given scope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24028008/