4

我正在用 JavaScript 编写一个简单的 REPL(读取、评估、打印、循环)实现。我能够像这样隔离代码和调用上下文:

var sandbox = {
  // Allow the input code to use predefined helper functions
  // without the preceding use of the this keyword.
  helper_fn: function() { alert("foo"); }
};

var func = new Function("with (this) { " + user_inputed_code + " }");
func.call(sandbox);

现在它关闭了,user_inputed_code以便this引用者sandbox以及输入的代码是否访问或改变this它正在影响sandbox

但是,我注意到,如果估算的代码不小心忘记在变量赋值前加上var全局命名空间被污染的关键字。

有没有办法防止这种情况发生?如果是这样(也许是正则表达式?)?有没有更好的方法来解决这个问题?

4

2 回答 2

2

我将提供两种与其他人在这里讨论的完全不同的方法。它们都很激烈,当您想要相对隔离环境时很有用。

  • 适用于所有浏览器的最简单的技术可能是创建一个 iframe,并将脚本标签附加到它。(请注意,如果它们在同一个域中,至少在旧版浏览器中,一个真正过分热心的 iframe 仍然可以克服这一点)。我在这个问题中讨论了这一点。
  • 使用 web Worker,默认情况下具有隔离环境,无法访问主执行线程的全局对象。我在这个问题中讨论了这一点。

更具体地说,如果您正在构建 REPL,请查看我们讨论的这个答案,我将解释如何使用 iframe 的第一种方法在相同范围但在全局范围之外评估代码。

(我假设一个浏览器,在节点中你可以简单地使用 vm 模块并在 runInContext 中选择上下文)

于 2013-07-26T13:23:14.713 回答
1

原来有一种方法有"use strict"和没有Object.freeze。您必须用自己的沙箱对象手动替换全局命名空间:

var sandbox, module, func, output;
// Empty object or with defined methods / properties
// you want to expose as globals.
sandbox = {};
// A reference to an object you WANT to provide safe
// access to. In this example it's just an empty object.
module = {};
// A better version of eval:
func = new Function("module", "with(this){return(function(module,global,window){\"use strict\";return eval(\"" + code + "\");})(module,this,this)}");
output = func.call(sandbox, module);

此代码允许 global 和 window 引用沙盒对象而不是全局名称空间。它将变量global和伪装成window沙箱对象,"use strict"如果输入未使用var. 它还将函数包装在一个with语句中,以使沙盒对象中定义的方法和属性能够像在this.. 要查看实现示例(带有测试规范),请查看此要点

谢谢大家的想法。希望这个答案对其他人有所帮助。

于 2013-07-26T12:42:51.583 回答