“放进沙箱里跑”听起来像是一条指令。实际上,人们说这句话时指的是四种常见边界之一,而它们拦住的东西大不相同。选错了,要么让你暴露在风险中,要么让每次运行都比必要的更慢、更贵。
本文的比较假设代码确实不可信:由语言模型编写、由用户提交,或来自一个你不认识的人的 pull request。你自己写的代码有不同的需求。
可能出什么问题
在比较边界之前,先说清楚它们是用来防什么的。不可信代码可能会:
- 读取不该读的东西: 环境变量、SSH 密钥、主目录里的文件、云元数据端点。
- 耗尽资源: 无限循环、不断 fork 直到机器卡死、写满磁盘。
- 滥用网络: 扫描其他主机、发送垃圾邮件、挖加密货币、调用你的内部服务。
- 持久驻留: 安装一个比任务活得更久的 cron 任务或服务。
- 逃逸: 利用下层的漏洞在宿主机本身上执行代码。
下面每个级别都只能处理其中的一部分。
级别 1:进程
最简单的沙箱是子进程:带超时的 subprocess.run,也许以单独的用户运行,如果你足够细致,还会加上资源限制和 seccomp 过滤器。
能拦住: 失控的运行时间(超时)、部分资源耗尽(限制)、部分危险的系统调用(seccomp)。 拦不住: 读取该用户能读的任何东西、网络访问、通过该用户可写的任何位置持久驻留,以及任何内核漏洞。 典型失效: 代码读到了一个你忘了是可读的文件,或者某个“受限”的语言解释器原来有后门。历史上满是没守住的语言内沙箱。
启动时间基本为零。对你自己写的代码没问题;对不是你写的代码,这算不上边界。
级别 2:容器
namespaces 让代码拥有自己的文件、进程和网络视图;cgroups 限制 CPU 和内存;去掉的 capabilities 和 seccomp 缩小了它能向内核请求的范围。
能拦住: 读取宿主机文件(除非被挂载进来)、看到其他进程、无限制地使用资源,以及在容器用完即丢时的大部分持久驻留问题。 拦不住: 共享的宿主机内核中的漏洞。机器上的每个容器都和同一个内核对话,所以一个可触及的内核漏洞就是出口。 典型失效: 配置问题,而不是什么奇特的漏洞利用。特权容器、把容器运行时的 socket 挂载进去、“只是为了调试”而开启宿主机网络。每一项都在悄悄拆掉边界。
启动时间是毫秒级。也有加固版本,包括在系统调用到达宿主机之前将其拦截的用户态内核,代价是一定的速度和兼容性。对于你信任的人写的代码,配置良好的容器是合理的默认选择。
级别 3:microVM
microVM 像完整虚拟机一样,在 hypervisor 下运行自己的内核,但几乎去掉了所有模拟硬件。Firecracker 是最知名的例子。
能拦住: 容器能拦住的一切,再加上共享内核问题。要触及宿主机,代码必须攻破 hypervisor 或少数几个虚拟设备之一,这个攻击面比内核的系统调用接口小得多。 拦不住: 滥用你交给它的东西。开放的出站流量仍可能被滥用;你注入的密钥仍可能泄露。 典型失效: 策略问题,而不是隔离问题。有人“为了让测试跑通”传进了生产环境的 token,或者给一个根本不需要出站流量的工作负载放开了出站限制。
启动时间从零点几秒到大约一秒,开销几 MB。这足够快,可以为每个任务创建一个、用完即删,这也顺带解决了持久驻留问题:没有任何东西可供回来。
级别 4:完整虚拟机
普通虚拟机或 VPS 的边界和 microVM 属于同一类:硬件虚拟化加 hypervisor。区别在于它周围的一切:完整的设备模型、完整的操作系统、需要的话还有公网 IP,以及以天或月计的生命周期。
能拦住: 与 microVM 同类的问题,但由于模拟的硬件更多,攻击面略大。 拦不住: 滥用它自身的网络身份。一台拥有公网 IP、运行着滥用代码的虚拟机,会让它自己的 IP 被列入黑名单;如果这个 IP 还负责发送你的邮件,那就麻烦了。(如果已经发生了,请看 IP 被列入黑名单时该怎么办。) 典型失效: 活得太久。一台为某次实验创建的虚拟机,不断积累凭据和状态,慢慢变成了它本该保护的那台可信机器。
启动时间从几十秒到几分钟,计费通常按月。这对需要入站端口的长期运行服务是合适的形态,对一次 20 秒的代码运行则是错误的形态。
对比
| 进程 | 容器 | microVM | 完整虚拟机 | |
|---|---|---|---|---|
| 独立内核 | 否 | 否 | 是 | 是 |
| 主要边界 | 用户权限 | namespaces + 共享内核 | hypervisor、极小设备模型 | hypervisor、完整设备模型 |
| 启动时间 | 约 0 | 毫秒 | 约 0.1–1 秒 | 10 秒 – 数分钟 |
| 开销 | 无 | 小 | 几 MiB | 几十到几百 MiB |
| 每个任务用完即丢 | 容易 | 容易 | 容易 | 慢、成本高 |
| 入站端口 / 公网 IP | 宿主机的 | 宿主机的 | 通常没有 | 有 |
如何选择
- 你或你的团队写的代码: 进程或容器就够了。
- 你自己分支的 CI: 在你的 runner 上用容器。
- 智能体生成的代码、用户提交、外部 pull request: 每个任务一个 microVM,用完删除。
- 必须接受连接或运行数周的不可信服务: 一台拥有独立 IP 的单独虚拟机,远离任何保存你凭据或发送你邮件的东西。
无论选哪种,都要额外遵守两条规则:不要往里面放任何你不愿交给代码作者的东西;有意识地决定网络可以做什么。
我们的产品处于什么位置
对于级别 3,我们提供代码沙箱:约一秒启动的 Firecracker microVM,可访问出站互联网,没有入站端口,按秒计费。它们正是为上面第三条而设计的;MCP 安全防护页面介绍了如何限制智能体能用它们做什么。对于级别 4,像 AI agent 套餐这样的 VPS 按月为你提供一整台机器。AI 智能体沙箱中的完整示例端到端展示了 microVM 模式,AI 智能体需要什么样的基础设施则把隔离作为多项需求之一来讨论。
评论
暂无评论。来做第一个吧。