如何使用javascript eval防止意外的全局名称空间污染?

时间:2013-07-26 03:04:48

标签: javascript

我正在用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作为变量赋值的序言,那么全局命名空间就会被污染。

反正有没有阻止这个?如果是这样(也许是正则表达式?)?有没有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分:2)

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

  • 适用于所有浏览器的最简单技术可能是创建一个iframe,并为其添加脚本标记。 (注意,如果他们在同一个域中,至少在旧浏览器中,真的过于热心的iframe仍然可以超越它)。我在this question中讨论了这个问题。
  • 使用web Workers,默认情况下具有隔离环境,并且无权访问主执行线程的全局对象。我讨论in this question

更具体地说,如果您正在构建REPL,请查看我们讨论的this answer,并使用iframe的第一种方法解释如何在相同范围内但在全局范围之外评估代码。 / p>

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

答案 1 :(得分: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);

此代码允许全局和窗口引用沙盒对象而不是全局名称空间。它伪装变量globalwindow作为沙箱对象,如果输入错过了"use strict"的使用,var的使用将导致它抛出异常。它还将函数包装在with语句中,以使沙盒对象中定义的方法和属性像this.前面一样工作。要查看实施示例(包含测试规范),请查看this gist

谢谢大家的意见。希望这个答案有助于其他人。