codepad.org和ideone.com这样的网站如何为您的程序创建沙盒环境?

37
我需要在我的网站上编译和运行用户提交的脚本,类似于codepadideone的功能。如何对这些程序进行沙箱处理,以防止恶意用户攻击我的服务器?
具体来说,我想将它们锁定在一个空目录中,并防止它们从该目录外读取或写入任何内容,防止它们消耗过多的内存或CPU,或者进行其他恶意操作。
我需要通过管道(stdin/stdout)与这些程序进行通信,而这些管道位于沙箱之外。

这个链接可能不会直接给你完整的答案,但会让你了解Sandboxie的工作原理。 - Pratik
1
@Pratik 那个视频已经不可用了。:( - Shaz
@Shaz 哎呀,那个链接上的视频已经被删除了,我会尝试找到其他的替代链接。 - Pratik
3个回答

24

codepad.org基于geordi开发,它使用chroot(即限制到文件系统的子树)和资源限制来运行一切,并使用ptrace API来限制不受信任程序对系统调用的使用。关于详情请参见 http://codepad.org/about

我之前也使用过Systrace,这是另一个用于限制系统调用的实用工具。

如果策略设置得当,则不受信任程序将被阻止破坏沙盒中的任何内容或访问它不应该访问的内容,因此可能没有必要将程序放入单独的chroot并为每个运行创建和删除它们。尽管那样做可以提供另一层保护,这也不会有什么坏处。


那么……你觉得我会手动创建一个沙盒,然后把所有东西都扔进去吗?不必为每个实例重新创建它们? - mpen

17

前不久我在寻找沙盒解决方案,用于计算机科学学生的自动化作业评估系统。就像其他所有东西一样,各种属性之间存在权衡:

  • 隔离和访问控制粒度
  • 性能和安装/配置的易用性

最终,我选择了基于Linux的多层架构:

  • 0级 - 虚拟化:

    通过在特定时间范围内的所有作业中使用一个或多个虚拟机快照,可以获得几个优点:

    • 敏感数据与非敏感数据的清晰分离。

    • 在期限结束时(例如每天一次或每个会话后),VM将从快照关闭并重新启动,从而删除任何恶意或非法代码残留。

    • 第一级计算机资源隔离:每个VM都具有受限的磁盘、CPU和内存资源,且主机机器无法直接访问。

    • 简单明了的网络过滤:通过在内部接口上拥有VM,主机上的防火墙可以有选择地过滤网络连接。

      例如,针对初级编程课程的学生进行测试的VM可以阻止所有传入和传出连接,因为这个级别的学生不会有网络编程作业。在更高的级别上,相应的VM可能会阻止所有传出连接,并只允许来自该学院内部的传入连接。

    还有意义的是,为Web-based提交系统单独设置一个VM - 这样的VM可以将文件上传到评估VM,但几乎不能做其他事情。

  • 1级 - 基本操作系统限制:

    在Unix OS上,它将包含传统的访问和资源控制机制:

    • 每个沙盒化程序都可以作为单独的用户执行,可能位于单独的chroot监狱中。

    • 严格的用户权限,可能包括ACL。

    • ulimit资源限制处理器时间和内存使用。

    • 使用 nice 命令来降低进程的优先级,以避免更重要的进程受到影响。在 Linux 上,还可以使用 ionicecpulimit 命令,但我不确定其他系统是否有类似命令。

    • 磁盘配额。

    • 按用户过滤连接。

    你可能需要以稍微更高权限的用户身份运行编译器,以获得更多内存和 CPU 时间、访问编译器工具和头文件等特权。

  • Level 2 - 高级操作系统限制:

    在 Linux 上,我认为需要使用 Linux 安全模块(如 AppArmorSELinux)来限制对特定文件和/或系统调用的访问。一些 Linux 发行版提供了一些沙箱安全配置文件,但正确配置这样的东西仍然可能是一个漫长而痛苦的过程。

  • Level 3 - 用户空间沙箱解决方案:

    我曾在小规模上成功使用过 Systrace,如我在这篇旧回答中提到的。Linux 还有许多其他沙箱解决方案,例如 libsandbox。这样的解决方案可能比基于 LSM 的替代方案提供更细粒度的对系统调用的控制,但可能会对性能产生可测量的影响。

  • Level 4 - 预防性打击:

    由于你将自己编译代码而非执行现有二进制文件,因此你手头有一些额外的工具:

    • 基于代码度量的限制;例如,一个简单的“Hello World”程序不应超过20-30行代码。

    • 有选择地访问系统库和头文件;如果您不想让用户调用connect(),可以限制对socket.h的访问。

    • 静态代码分析;禁止汇编代码、“奇怪”的字符串文字(即shell-code)和使用受限制的系统函数。

    一位熟练的程序员可能能够绕过这些措施,但随着成本效益比例的增加,他们将变得不太可能坚持。

  • 0-5级监控和日志记录:

    您应该监视系统的性能并记录所有失败的尝试。不仅可以更有可能在系统级别中断正在进行的攻击,而且您可能还可以利用行政手段保护您的系统,例如:

    • 联系负责此类问题的安全官员。

    • 找到那个顽固的黑客,并为其提供一份工作。

您需要的保护程度以及愿意花费多少资源来设置它,取决于您自己。


1
据我所知,systrace本质上是一个系统调用过滤器。我不记得它是否具有任何资源控制功能,但在Unix/Linux世界中,堆叠ulimitniceionice等是相当标准的。至于程序,只要systrace不决定阻止系统调用,它们就像在systrace之外一样工作,尽管速度会慢得多... - thkala
当您使用 chroot 时,如何防止用户仅执行 exit - Yahya Uddin
1
在这种情况下,exit 终止了 chroot 会话,因此也终止了该特定用户的会话。它不会返回到 shell,要么是因为通过 exec 替换了 shell,要么是因为一开始就没有通过 shell 启动。 - thkala
你说的通过 exec 替换 shell 是什么意思?另外,除非在 shell 中执行,否则你还能以其他方式启动 chown 会话吗?(注意,我正在尝试在 chown 会话中执行脚本(例如 php、java、bash 等)。) - Yahya Uddin
@YahyaUddin: 1. 参见execve(2) 或者在Bash中输入help exec命令查看输出。2. 任何具有CAP_SYS_CHROOT功能权限(通常为以root身份运行的程序)的程序都可以在chroot中启动受限进程。请参阅chroot(2) - thkala
显示剩余2条评论

8

我是@thkala提到的libsandbox的开发者,我建议在您的项目中使用它。

对于@thkala的回答,我有一些额外的评论:

  1. libsandbox分类为用户空间工具是公平的,但libsandbox确实集成了标准的操作系统级别安全机制(即chroot、setuid和资源配额);
  2. 限制访问C/C++头文件或分析用户代码的静态分析并不能防止调用系统函数如connect()。这是因为用户代码可以(1)自己声明函数原型而不包括系统头文件,或者(2)在libc的包装函数中不触及底层的内核级别系统调用来调用它们;
  3. 编译时保护也值得注意,因为恶意的C/C++代码可以通过无限的模板递归或预处理宏扩展耗尽您的CPU;

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