我试图在Linux + Node.js中使用沙盒模块来运行不受信任的JavaScript代码,但它无法正常工作。我只需要让用户编写打印一些文本的JavaScript程序。不允许其他输入/输出,并且仅使用纯JavaScript语言,不能使用其他的Node.js模块。 如果这样做实在不可能,您建议使用哪种语言来完成此类任务?我需要的最小功能集包括一些数学、正则表达式、字符串操作和基本的JSON函数。 脚本最多可以运行5秒钟,然后进程将被终止,我该如何实现?
我试图在Linux + Node.js中使用沙盒模块来运行不受信任的JavaScript代码,但它无法正常工作。我只需要让用户编写打印一些文本的JavaScript程序。不允许其他输入/输出,并且仅使用纯JavaScript语言,不能使用其他的Node.js模块。 如果这样做实在不可能,您建议使用哪种语言来完成此类任务?我需要的最小功能集包括一些数学、正则表达式、字符串操作和基本的JSON函数。 脚本最多可以运行5秒钟,然后进程将被终止,我该如何实现?
我见过在此类问题中提到的所有库(vm2
,jailed
)都试图隔离node
进程本身。这些类型的“监狱”不断被攻破,并且高度依赖于node
标准库的未来升级,以避免暴露其他攻击向量。
另一种选择是直接使用V8 :: Isolate
类。它旨在隔离Google Chrome和node
中的JavaScript,因此您可以期望它得到充分维护,并比您、我或单个库维护者更加安全。
该类仅能运行“纯”JavaScript
。它具有完整的ECMAScript实现,但没有浏览器API或node
API。
这是Cloudflare
为其Worker产品使用的内容。
deno
,由node
的创建者开发的新语言,采用默认沙箱化的雄心壮志,使用完全相同的方法并根据启用的标志公开标准库的部分内容。
node
环境中,你可以使用isolated-vm
库。它是一个非常棒的库,可以创建与要在隔离中运行的代码分离的v8::Isolate
子进程。node
版本的更新,它会自动更新,因为它使用了node
自己的v8::Isolate
。webpack
来将所有东西打包在一个单独的脚本中,让库能够使用它。V8::Isolate
吗?如果是的话,那么段落间距应该被修复。 - collimarco我最近为沙盒化不受信任的代码创建了一个库,它似乎符合要求(在Node.js中以受限进程执行代码,在Web浏览器中使用沙盒内的iframe中的Worker执行):
https://github.com/asvd/jailed
有机会将主应用程序中给定的一组方法导出到沙盒中,从而提供任何自定义API和一组权限(实际上,这就是我决定从头开始制作库的原因)。所提到的数学、正则表达式和字符串相关内容由JavaScript本身提供,任何其他内容都可以明确地从外部导出(例如用于与主应用程序通信的某些函数)。
很晚了,回答这个问题可能有点晚,我想下面的工具可能是一个有价值的补充,以上回答/评论中没有提到。
我正在尝试实现类似的用例。在查阅了网络资源后,https://www.npmjs.com/package/vm2 似乎很好地处理了沙盒环境(nodejs)。
它基本上满足了沙盒特性,如限制对内置或外部模块的访问、沙盒之间的数据交换等。
虽然回答晚了,但也许是一个有趣的想法。
静态代码分析 => AST 操作 => 代码生成
例如,一个函数如下所示:
function () {
a = 1;
window.b = 1;
eval('window.c()');
}
function () {
var a, window = {}, eval = function () {}; // variable overwriting
a = 1;
window.b = 1;
eval('window.c()');
}
就这样。
应考虑更多的覆写,例如eval()
、new Function()
和其他全局对象或API。在解析过程中应该对警告进行良好的组织和报告。
一些相关工作的顺序:
我基于以上做法的实践是function-sandbox。
我现在也面临着类似的问题,而且我只看到了关于沙盒模块的负面评价。
如果您不需要任何特定于节点环境的内容,我认为最好的方法是使用无头浏览器,例如PhantomJS或Chimera作为沙盒环境。
V8::Isolate
的组合以及其他一些技术。这不仅使得安全性得到保障,而且速度也非常快。我们还添加了自己的fetch()
等集成,因为V8不支持Web或Node特定的APIs。这进一步允许我们做一些很棒的事情,比如限制脚本可以通信的端点,甚至通过注入预配置的Authorization
标头来预认证请求/域名。问问自己以下问题:
正如你通过sandbox module的实验已经知道的那样,编写自己的沙盒并不容易。沙盒的主要问题在于你必须做到万无一失。一个错误将完全破坏你的安全性,这就是为什么浏览器开发人员与全球的黑客进行持续战斗。
话虽如此,简单的沙盒还是相当容易实现的。首先,你需要编写自己的JavaScript解释器,因为你不能使用node.js的解释器,因为它包含eval()
和require()
(这两个函数都会让黑客逃离你的沙盒)。
解释器必须确保被解释的代码不能访问除你提供的少量全局符号以外的任何内容。这意味着不能有eval()
函数,例如(或者你必须确保该函数只在你自己的JavaScript解释器的上下文中被评估)。
这种方法的缺点是:需要大量工作,如果在解释器中犯了一个错误,黑客可以离开沙盒。
另一种方法是清理代码并使用node.js的eval()
运行它。您可以通过运行一堆正则表达式来清理现有代码,例如/eval\s*[(]//g
以删除恶意代码部分。
这种方法的缺点是:很容易犯一个错误,使您容易受到攻击。例如,可能会存在正则表达式和node.js之间的不匹配,导致它们对“空格”的理解不同。一些晦涩的Unicode空格可能会被解释器接受,但不会被正则表达式接受,这将允许攻击者运行eval()
。
我的建议是:编写一个小型演示测试用例,展示沙盒模块如何被破坏,并进行修复。这将节省您大量的时间和精力,如果沙盒中存在漏洞,那么这不会完全是您的错。
eval()
。一些“聪明人”通过添加var __ev = eval; eval = null;
来“修复”问题,因为“没有人会发现这个问题”(安全性靠混淆)。 - Aaron Digulla
http://gf3.github.com/sandbox/
吗? - alessioalex