Node.JS vm.runInNewContext()与require()和eval()的区别

10
  • vm.runInNewContext 是否像 eval 一样被视为黑魔法?
  • require 和读取文件并使用 vm 运行它之间是否存在显着的性能差异,如果实现缓存并只想向上下文中添加一些变量,那么底层是否相同?
2个回答

12
如果你查看实现node.js模块加载的代码,可以看到 require 在幕后使用了 vm.runInNewContextvm.runInThisContext。 然而,require 还会做一些其他额外的事情,例如缓存模块。
Node 文档 演示了 vm 命令和 eval 之间的行为类似但不同的方式。
因此,require、eval 和 vm 都有一些不同,但都可以用于加载代码。如果您正在加载来自客户端的任意代码,则它们都具有类似的安全问题。

1
仅供记录,由于上面链接到node.js的源代码是“古老的”,这里提供一个更近期的7.10.0源代码链接:https://github.com/nodejs/node/blob/v7.10.0/lib/module.js#L543。他们使用`vm.runInThisContext`或`vm.runInDebugContext`。关于`eval`,使用逗号表达式`(0, eval)(....)`,您可以在全局范围内评估脚本,以便它不会像在搜索页面上的“eval”时在node.js文档链接示例中污染本地范围。 - Mörre
1
"注释维护": 这次提供的是 Node.js 11.9.0 的新源代码链接:https://github.com/nodejs/node/blob/v11.9.0/lib/internal/modules/cjs/loader.js#L694 - Mörre

6

runInNewContext并不是作为requireeval的替代品,而是作为创建沙箱环境的一种方式,您可以在其中安全地运行其他脚本。

缺点是它很慢(需要大约10毫秒来创建)并且占用几兆字节。因此,不要将其用作require的替代品。


1
那么,如果我要使用它来加载控制器对象(/controllers/blog_controller.js)并在上下文中包含一些帮助程序,几乎没有性能损失,对吗?(控制器仅加载一次) - Christopher Tarquini
不要这样做。这被认为是一种非常糟糕的通用实践。你为什么认为需要对自己的控制器代码进行沙盒处理? - Jan Jongboom
1
同样的原因railway-js使用它,为控制器提供更丰富的上下文,不过我发现了一个比使用vm更好的解决方案。谢谢! - Christopher Tarquini
11
嗨,克里斯,你有更好的解决方案吗? - user766987

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接