如何在Node.js沙盒中安全地运行用户提交的脚本?

62

有哪些选项可以在node.js中安全地运行(可能是恶意的)用户提交的脚本?即在一个防止代码访问敏感数据和API的环境中?

vm.runInNewContext(userScript, {})是一个诱人的起点......但似乎存在已知问题

sandbox模块看起来很有趣,但也使用了runInNewContext(),所以我有点不放心。


我建议使用 vm,因为它是 Node 核心的一部分。由于 Node 核心往往会修复其错误,所以可以假定问题将得到解决。 - Raynos
@Raynos 这不是一个 bug。文档说它只适用于已知好的代码。 - thejh
@thejh - 真的,但API本身倾向于让人相信代码正在完全不同的上下文中执行,这意味着该代码不应该能够访问当前上下文。而我期望API的意图正是如此-提供一个沙箱来运行脚本。因此...我认为可以有一个相当有力的理由证明这只是一个很好记录的bug. :) - broofa
这个回答解决了你的问题吗?如何在服务器端运行不受信任的代码? - Jerska
2个回答

40
您应该始终在一个单独的进程中运行不受信任的代码,这正是沙盒模块所做的。简单的原因是 vm.runInNewContext('while(true){}', {}) 会冻结Node。
它首先会生成一个单独的进程,稍后将在其标准输出中将结果序列化为JSON格式发送。无论子进程做什么,父进程都会继续执行,并且可以触发超时机制。
接下来,将不受信任的代码封装在一个闭包中并使用严格模式进行了包装。最后,传递一个非常有限的global对象以防止访问Node的API。不受信任的代码只能进行基本计算,没有文件或套接字的访问权限。
虽然建议您阅读沙盒的代码,但我不建议直接使用它:
  • 该代码已经过时,7个月未更新。
  • Node中的Child Process模块已经提供了大多数所需功能,特别是child_process.fork()
  • child_process.fork提供的IPC通道可能具有更好的性能。
为了增加安全性,您还可以考虑使用setuid-sandbox。这是Google Chrome用于防止选项卡进程访问文件系统的代码。您需要制作一个本地模块,但是这个例子似乎很简单。

4
vm 模块中的方法现在支持 timeout 参数,可以安全地执行 while(true) {}。这显然不能解决安全问题,但能够解决无限循环的问题。 - Andrew Paprocki
@AndrewPaprocki,您能否提供超时显示的文档链接? - Rob Fox
1
这个答案非常好。不过,我想指出另一个类似的问题(更近期的),可能对有同样问题的人有所帮助:https://dev59.com/gmMm5IYBdhLWcg3wlfpS - Akhorus

16

这里有一个叫做vm2的新模块在GitHub上发布,专门解决一些问题,特别是在Node.JS应用程序中。或许这会像我一样帮助其他人找到它。


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