我正在尝试使用沙盒模块在linux + node.js中运行不受信任的javascript代码但是它已经坏了,我只需要让用户编写打印出一些文本的javascript程序。不允许其他i / o,只使用普通的javascript,没有其他节点模块。 如果不是真的可以这样做,你建议用什么其他语言来完成这项任务?我需要的最小特征集是一些数学,正则表达式,字符串操作和基本的JSON函数。 脚本将运行让我们说5秒钟顶部然后该过程将被杀死,我怎么能实现呢?
答案 0 :(得分:7)
我最近创建了一个用于沙箱化不受信任代码的库,它似乎符合要求(在Node.js的情况下在受限制的进程中执行代码,在用于Web浏览器的沙盒iframe中的Worker中执行):
https://github.com/asvd/jailed
有机会将给定的一组方法从主应用程序导出到沙箱中,从而提供任何自定义API和一组权限(该功能实际上是我决定从头开始创建库的原因)。所提到的数学,正则表达式和字符串相关的东西是由JavaScript本身提供的,任何其他东西都可以从外部显式导出(就像某些函数用于与主应用程序通信)。
答案 1 :(得分:3)
我在这些问题(vm2
,jailed
)中提到的所有库都试图隔离node
进程本身。这类“监狱”不断地被破坏,并且高度依赖于将来对node
标准库的升级,从而不会暴露出另一种攻击媒介。
一种替代方法是直接使用V8::Isolate
类。它旨在将JavaScript隔离在Google Chrome和node
中,因此您可以期望它得到完全维护,并且比我或一个库维护者所能做到的更加安全。
此类只能运行“纯” JavaScript
。它具有完整的ECMAScript实现,但没有浏览器API或node
API。
Cloudflare
为其Worker产品使用的内容。
deno
是node
的创造者开发的新语言,它的野心是默认使用完全相同的东西进行沙盒化,并根据您启用的标志公开标准库的某些部分。
在node
环境中,您可以使用isolated-vm
。这是一个了不起的库,它使用您要独立运行的代码创建v8::Isolate
d个子流程。
它提供了将值和函数传递给隔离区并返回的方法。使用起来并不比大多数“监狱”库简单,但是可以保证您对JavaScript代码进行了实际的沙箱处理。
由于它是“纯” JavaScript,因此唯一的转义是您以注入函数形式提供的转义。
另外,由于它使用node
自己的node
,因此每个v8::Isolate
版本都会自动更新。
主要的麻烦之一是,如果要在脚本中注入库,则可能需要使用webpack
之类的打包程序,以便将所有内容捆绑在一个可以由库使用的脚本中。 / p>
我个人使用它在搜寻器中运行用户提供的代码,以使用用户提供的代码从网页中提取信息,并且它产生了奇迹。
答案 2 :(得分:2)
沙箱的基本思想是,你需要预定义为全局变量的变量来做东西,所以如果你通过取消设置来拒绝它们,或者用受控制的替换它们,它就无法逃脱。只要你不忘记任何事情。
首先替换deny require()或用受控制的东西替换它。 不要忘记过程和"全球" a.k.a" root",困难的事情是不要忘记任何事情,这就是为什么依靠别人建造沙箱的好处; - )
答案 3 :(得分:2)
知道它很晚才回答这个问题,猜测下面的工具可能是一个增值值,在上面的答案/评论中没有提到。
尝试实现类似的用例。在浏览完Web资源后,https://www.npmjs.com/package/vm2似乎正在很好地处理沙箱环境(nodejs)。
它非常满足沙盒功能,例如限制对内置或外部模块的访问,沙箱之间的数据交换等。
答案 4 :(得分:1)
如果你能负担得起性能,你可以在具有适当CPU和内存限制的一次性虚拟机中运行JS。
当然,您相信VM解决方案的安全性。通过将它与普通的JS沙箱一起使用,您将拥有两层安全性。
对于其他图层,请将沙箱放在与主应用程序不同的物理计算机上。
答案 5 :(得分:1)
Docker.io块上有一个很棒的新手,它使用LXC和CGroups来创建沙箱。
以下是使用online gist和codepad.org
的Docker(类似于Go Lang)的一种实现方式这只是为了证明可以安全地运行Docker Containers内的许多编程语言编写的不受信任的代码,包括node.js
答案 6 :(得分:0)
问自己这些问题:
正如您通过sandbox module的实验所知,编写自己的沙箱并非易事。沙箱的主要问题是你必须把一切都弄好。一个错误将彻底破坏您的安全性,这就是为什么浏览器开发人员与全球各地的破解者进行持续战斗的原因。
尽管如此,简单的沙箱很容易做到。首先,您需要编写自己的JavaScript解释器,因为您不能使用node.js中的那个,因为eval()
和require()
(两者都允许破解者逃离您的沙箱)。
除了您提供的少数全局符号之外,解释器必须确保解释的代码不能访问任何内容。这意味着不能有eval()
函数(或者您必须确保此函数仅在您自己的JavaScript解释器的上下文中进行评估)。
这种方法的缺点:很多工作,如果你在翻译中犯了错误,那么破解者可以离开沙箱。
另一种方法是清理代码并使用node.js的eval()
运行它。您可以通过在/eval\s*[(]//g
上运行一堆正则表达式来清除现有代码,以删除恶意代码部分。
这种方法的缺点:很容易犯错,让你容易受到攻击。例如,regexp和node.js之间可能存在不匹配的“空白”。解释器可能会接受一些模糊的unicode空格,但regexp不会允许攻击者运行eval()
。
我的建议:编写一个小型演示测试用例,显示沙盒模块是如何破坏并修复的。它将为您节省大量的时间和精力,如果沙盒中存在错误,那么这不是您的错(嗯,至少不完全是这样)。
答案 7 :(得分:0)
我现在面临类似的问题而且我只阅读有关沙箱模块的坏事。
如果您不需要特定于节点环境的任何内容,我认为最好的方法是使用无头浏览器(如PhantomJS或Chimera)作为沙箱环境。
答案 8 :(得分:0)
迟到的答案,但也许是一个有趣的想法。
静态代码分析 => AST操作 => 代码生成
例如,函数如下所示:
function () {
a = 1;
window.b = 1;
eval('window.c()');
}
基于JS代码解析器的静态分析使我们能够在原始函数体之前插入变量声明语句:
function () {
var a, window = {}, eval = function () {}; // variable overwriting
a = 1;
window.b = 1;
eval('window.c()');
}
那就是它。
应考虑更多重写,例如eval()
,new Function()
和其他全局对象或API。解析过程中的警告应该很好地组织和报告。
按顺序完成一些相关工作:
基于以上所述的做法是function-sandbox。