关于javascript:如何在不受信任的代码服务器端运行?

How to run untrusted code serverside?

我正在尝试使用沙盒模块在linux + node.js中运行不受信任的javascript代码,但是它坏了,我需要做的就是让用户编写可打印一些文本的javascript程序。 不允许其他I / O,只能使用普通的javascript,不能使用其他节点模块。
如果真的不可能做,那么您建议使用哪种其他语言进行此类任务? 我需要的最小功能集是一些数学,正则表达式,字符串操作和基本JSON函数。
脚本将运行5秒钟,然后终止进程,我该如何实现?


我最近创建了一个库,用于对不受信任的代码进行沙箱处理,它似乎符合要求(在使用Node.js的情况下,在受限制的过程中以及在用于Web浏览器的沙箱iframe内的Worker中执行代码):

https://github.com/asvd/jailed

有机会从主应用程序中将给定的方法集导出到沙箱中,从而提供任何自定义API和特权集(该功能实际上就是我决定从头开始创建库的原因)。所提到的数学,正则表达式和与字符串相关的内容由JavaScript本身提供,任何其他内容都可以从外部显式导出(例如与主应用程序进行通信的某些功能)。


知道它回答问题的时间很晚,猜测下面的工具可能是一个增值,上面的答案/评论中没有提到。

尝试实现类似的用例。浏览完网络资源后,https://www.npmjs.com/package/vm2似乎可以很好地处理沙盒环境(nodejs)。

这几乎满足了沙箱功能,例如限制对内置或外部模块的访问,沙箱之间的数据交换等。


Docker.io是一个很棒的新手,它使用LXC和CGroups创建沙箱。

这是使用Docker和Go Lang的在线要点(类似于codepad.org)的一种实现

这只是证明了一个人可以安全地运行Docker容器内以多种编程语言编写的不受信任的代码,包括node.js


沙箱的基本思想是,您需要将预定义为全局变量的变量用于处理工作,因此,如果您通过取消设置脚本或将脚本替换为受控脚本来拒绝脚本,则脚本将无法转义。只要您什么都不忘记。

首先替换拒绝require()或将其替换为受控对象。
不要忘记流程和"全局"(也称为"根"),困难的是不要忘记任何东西,这就是为什么依靠别人建立了沙箱是一件好事;-)


如果可以承受性能损失,则可以在具有适当CPU和内存限制的一次性虚拟机中运行JS。

当然,那么您可以信赖VM解决方案的安全性。通过将其与普通的JS沙箱结合使用,您将获得两层安全性。

对于附加层,请将沙箱放置在与主应用程序不同的物理计算机上。


我在这些问题(vm2jailed)中提到的所有库都试图隔离node进程本身。这类"监狱"不断被破坏,并高度依赖于将来对node标准库的升级,以不暴露其他攻击媒介。

另一种选择是直接使用V8::Isolate类。它旨在将JavaScript隔离在Google Chrome和node中,因此您可以期望它得到完全维护,并且比我或一个库维护者所能做到的更加安全。
该类仅能运行" pure" JavaScript。它具有完整的ECMAScript实现,但没有浏览器API或node API。

这是Cloudflare用于其Worker产品的功能。
denonode的创建者开发的新语言,默认情况下会使用完全相同的东西进行沙箱化,并根据启用的标志公开标准库的某些部分。

node环境中,可以使用isolated-vm。这是一个了不起的库,它使用您要独立运行的代码创建V8::Isolate d子流程。

它提供了将值和函数传递给隔离对象并返回的方法。与大多数"监狱"库相比,使用它并不那么简单,但是可以保证您对JavaScript代码进行了实际的沙箱处理。
由于它是"纯" JavaScript,因此唯一的转义是您以注入函数的形式提供的转义。
此外,由于它使用node自己的V8::Isolate,因此会随每个node版本自动更新。
主要的麻烦之一是,如果要在脚本中注入库,则可能需要使用webpack之类的打包程序,以便将所有内容捆绑在一个可以由库使用的脚本中。

我个人使用它来在搜寻器中运行用户提供的代码,以使用用户提供的代码从网页中提取信息,并且它产生了奇迹。


答案较晚,但可能是一个有趣的想法。

静态代码分析=> AST操作=>代码生成

  • 静态分析将解析源代码的AST。 AST
    提供了一个通用的数据结构,使我们可以遍历和修改
    源代码。
  • 通过AST操作,我们可以找出所有标识符
    引用外部作用域中的任何敏感变量。要是我们
    需要时,我们可以在开始时重新声明并初始化它们
    函数体,以覆盖它们。因此,从内部到外部的引用都处于控制状态。
  • 从AST生成代码也很容易。
  • 例如,一个函数如下所示:

    1
    2
    3
    4
    5
    function () {
        a = 1;
        window.b = 1;
        eval('window.c()');
    }

    基于JS代码解析器的静态分析使我们能够在原始函数体之前插入变量声明语句:

    1
    2
    3
    4
    5
    6
    function () {
        var a, window = {}, eval = function () {}; // variable overwriting
        a = 1;
        window.b = 1;
        eval('window.c()');
    }

    而已。

    应该考虑更多的覆盖,例如eval()new Function()和其他全局对象或API。解析期间的警告应组织得井井有条,并予以报告。

    一些相关的工作顺序如下:

    • esprima,用于多用途分析的ECMAScript解析基础结构。
    • estraverse,ECMAScript JS AST遍历函数。
    • escope,ECMAScript范围分析器。
    • escodegen,ECMAScript代码生成器。

    基于以上内容,我的实践是功能沙箱。


    我现在正面临类似的问题,并且我只阅读有关沙盒模块的坏消息。

    如果您不需要特定于节点环境的任何东西,那么我认为最好的方法是使用无头浏览器(例如PhantomJS或Chimera)作为沙盒环境。


    问自己以下问题:

  • 您是地球上最聪明的人之一吗?
  • 您是否会经常拒绝Google,Mozilla和Kaspersky Lab的工作机会,因为这会让您感到厌烦?
  • "不受信任的代码"来自与您在同一公司工作的人还是来自全球各地的犯罪分子和无聊的计算机孩子?
  • 您确定node.js没有安全漏洞可能会通过沙盒泄漏吗?
  • 您可以编写完美的100%无错误代码吗?
  • 您是否了解JavaScript的所有知识?
  • 正如您通过沙盒模块的实验所知道的那样,编写自己的沙盒并不容易。沙箱的主要问题是您必须正确处理所有问题。一个错误将完全破坏您的安全性,这就是为什么浏览器开发人员与全球的饼干者不断进行战斗的原因。

    也就是说,简单的沙箱非常容易做到。首先,您需要编写自己的JavaScript解释器,因为由于eval()require(),您无法使用来自node.js的解释器(这两者都会使破解者逃脱沙箱)。

    解释器必须确保所解释的代码除了您提供的几个全局符号以外,不能访问任何其他内容。例如,这意味着没有eval()函数(或您必须确保仅在您自己的JavaScript解释器的上下文中评估此函数)。

    这种方法的缺点:大量的工作,如果您在解释器中犯了一个错误,那么饼干可以离开沙箱。

    另一种方法是清除代码并使用node.js的eval()运行它。您可以通过像/eval\\s*[(]//g那样运行一堆正则表达式来清除现有代码,以删除恶意代码部分。

    这种方法的缺点:容易犯一个错误,使您容易受到攻击。例如,正则表达式和node.js认为的"空白"之间可能不匹配。解释器可能会接受某些晦涩的unicode空白,但正则表达式不能接受,这会使攻击者运行eval()

    我的建议:编写一个小型演示测试用例,以显示沙盒模块如何损坏并修复。这将节省您大量的时间和精力,并且如果沙箱中有错误,那也不是您的错(嗯,至少不是全部)。