slash-init/sandboxed-code-runner
GitHub: slash-init/sandboxed-code-runner
一个基于 Docker 容器多层隔离机制的安全沙盒代码执行后端,用于在严格资源约束下安全运行不受信任的用户代码。
Stars: 0 | Forks: 0
# 沙盒代码执行后端
一个在隔离的、资源受限的 Docker 容器中执行用户提交代码的后端服务。
该系统被设计为一个针对不受信任代码的**沙盒执行引擎**,重点关注正确性、隔离性和生命周期控制,而非 UI 或编辑器功能。
## 项目存在的原因
执行任意用户代码本质上是危险的。直接在服务器上运行程序可能导致:
- 无限循环耗尽 CPU
- 内存耗尽
- Fork 炸弹
- 僵尸进程
- 未授权的文件系统访问
- 基于网络的攻击
- 容器逃逸尝试
本项目演示了如何通过在具有严格资源限制和强制终止的一次性受限容器中运行每次执行,来降低这些风险。
本项目定位为一个**专注于系统层面的后端项目**,而不是一个玩具编译器。
## 核心理念
- 用户代码永远不会在宿主机上执行
- 每个请求都在其独立的一次性 Docker 容器中运行
- CPU、内存、进程数和执行时间受到严格限制
- 容器具有明确的命名,并在超时时被强制杀死
- 所有执行产物都是临时的,并会被自动清理
- 执行结果包含分类后的状态
- 完全禁用网络访问
- 容器以降级权限和只读文件系统运行
- 以非 root 用户执行以提供额外的安全性
## 高层架构
1. 客户端通过 HTTP POST 将源代码和语言类型发送到 `/run`
2. 后端验证语言并生成唯一的作业 ID
3. 创建一个临时执行目录
4. 将源代码和输入写入文件
5. 启动一个 Docker 容器,包含:
- 有限的 CPU(1 核)和内存(256MB)
- 有限的进程数(64)
- 无网络访问(`--network=none`)
- 丢弃所有权限(`--cap-drop=ALL`)
- 只读文件系统(`--read-only`)
- 非 root 用户执行
- 挂载的执行目录(读/写覆盖层)
6. 程序输出通过 spawn 以流式传输回后端
7. 使用 `docker kill` 强制执行 2 秒超时
8. 在完成或超时后:
- 容器被自动移除(`--rm`)
- 临时文件被删除
9. 向客户端返回带有状态分类的结构化结果
## 技术栈
- **运行时**: Node.js (Express)
- **容器化**: Docker
- **进程管理**: Node.js `spawn`(流式处理,无 shell 开销)
- **速率限制**: express-rate-limit
- **沙盒镜像**:
- Python 3.11 (slim 变体)
- GCC 13
- **安全性**: 具有资源限制的多层容器隔离
该架构与语言无关,并支持添加额外的运行时。
## API 规范
### 端点
`POST /run`
### 请求体
```
{
"language": "python" | "cpp",
"code": "source code as string",
"input": "stdin input as string (optional)"
}
```
### 响应格式
每次执行均返回:
```
{
"status": "success | runtime_error | timeout",
"stdout": "program output",
"stderr": "error output"
}
```
**状态分类**:
- `timeout`:执行超过了 2 秒限制
- `runtime_error`:程序产生了 stderr 输出
- `success`:无错误地干净执行
## 沙盒保证
每次执行均受以下约束:
- **CPU 限制**: 最多 1 核
- **内存限制**: 最多 256MB
- **进程数限制**: 最多 64 个进程
- **硬性执行超时**: 2 秒(通过 `docker kill` 强制执行)
- **网络隔离**: 完全禁用网络栈
- **文件系统隔离**: 只读根文件系统
- **权限隔离**: 丢弃所有 Linux capabilities
- **用户隔离**: 以非 root 用户 `sandbox-user` 运行
- **显式容器终止**: 超时时会杀死具名容器
- **自动清理**: 容器移除和临时文件删除
这可以防止常见的滥用模式,如无限循环、内存炸弹、Fork 炸弹、残留进程、网络攻击和权限升级。
## 安全特性
### 多层防御
1. **容器隔离**: 每次执行都在独立的命名空间中
2. **资源限制**: Cgroups 防止资源耗尽
3. **网络拒绝**: `--network=none` 阻止所有网络连接
4. **权限丢弃**: `--cap-drop=ALL` 移除内核权限
5. **只读文件系统**: `--read-only` 防止持久化攻击
6. **非 Root 用户**: 降低容器逃逸风险
7. **速率限制**: 每个 IP 每 15 分钟 100 个请求
8. **强制终止**: 通过杀死容器实现手动超时
### 防护范围
- ✅ 无限循环
- ✅ 内存炸弹
- ✅ Fork 炸弹
- ✅ CPU 耗尽
- ✅ 网络攻击
- ✅ 权限升级尝试
- ✅ 持久性文件系统修改
- ✅ 通过速率限制防止 API 滥用
## 项目结构
```
executions/ # Temporary per-request directories (auto-deleted)
sandbox/
cpp/
Dockerfile # GCC 13 with non-root user
python/
Dockerfile # Python 3.11-slim with non-root user
src/
app.js # Express app setup
server.js # Server entry point (port 3000)
config/
limits.js # Rate limiting configuration
runtimes.js # Language runtime definitions
routes/
run.routes.js # POST /run endpoint
services/
execution.service.js # Core execution logic with spawn
package.json
```
### 关键文件
- **sandbox/**: 包含安全配置的、针对特定语言的 Dockerfile
- **executions/**: 用于每次请求文件的临时目录(自动创建/删除)
- **src/config/runtimes.js**: 将语言映射到 Docker 镜像和源文件名
- **src/services/execution.service.js**: 基于流式输出和超时处理的 Spawn 执行
## 如何运行
### 前置条件
- Node.js 18+
- 已安装并正在运行 Docker
- 构建 sandbox 镜像:
```
cd sandbox/python && docker build -t python-sandbox .
cd ../cpp && docker build -t cpp-sandbox .
```
### 启动服务器
```
npm install
npm run dev
```
服务器在 3000 端口运行。
### 示例请求
```
curl -X POST http://localhost:3000/run \
-H "Content-Type: application/json" \
-d '{
"language": "python",
"code": "print(\"Hello, World!\")",
"input": ""
}'
```
## 当前限制
- 有限的运行时集合(Python, C++)
- 无身份验证或用户账户
- 无持久化存储或执行历史
- 返回完整的 stderr(潜在的信息泄露)
- 基于时间戳的作业 ID(高负载下存在冲突风险)
- 单服务器架构(无水平扩展)
- 最多 5 个并发执行(可通过 execution.service.js 中的 `MAX_EXECUTIONS` 配置)
这些都是为了保持对沙盒执行基本原理的关注而做出的权衡。
## 预期用途
- 学习系统级后端概念
- 演示基于容器的沙盒技术
- 理解进程隔离和资源限制
- 作品集或学术项目
- 在线判题系统或执行服务的基础
- 安全代码执行的学习材料
## 为什么选择 Spawn 而不是 Exec?
该实现使用 Node.js 的 `spawn` 而不是 `exec`,原因如下:
1. **流式处理**: 实时收集 stdout/stderr,无需缓冲
2. **无 Shell 开销**: 直接执行进程
3. **更好的控制**: 通过容器名称实现手动超时控制
4. **内存效率**: 无需缓冲全部输出
## 免责声明
本项目演示了隔离技术,但如果要在恶劣的生产环境中部署,不能直接原样使用,还需要额外的加固、监控和安全控制。
生产环境部署的具体注意事项:
- 容器镜像漏洞扫描
- 错误信息清理
- 身份验证与授权
- 日志与审计追踪
- 水平扩展与负载均衡
- 用于存储执行历史的数据库
- 增强的输入验证
## 作者
本项目构建用于探索执行管道、进程隔离和容器生命周期管理。
标签:C++, Docker, GNU通用公共许可证, Go, HTTP API, MITM代理, NIDS, Node.js, Python, Ruby工具, 代码执行引擎, 代码沙箱, 后端服务, 子域名枚举, 安全, 安全防御评估, 容器化, 容器逃逸防护, 数据擦除, 无后门, 无网络访问, 权限最小化, 沙箱, 系统安全, 系统设计, 脚本检测, 请求拦截, 资源限制, 超时处理, 进程控制, 防恶意代码, 防拒绝服务, 隔离执行, 面试项目