适用场景
当编码智能体(AI 词典:AI Agent">AI Agent、自动化脚本、CI 里的模型产物)开始真正"动手跑代码"时,风险从"答错话"变成"删错文件、读到密钥、连上外网"。这套方案用 MXC 在 Windows 上拉起一个一次性、策略驱动的沙箱,把智能体生成的代码关进去跑,只允许它看一个输入目录、写一个临时目录,出沙箱的东西全部当不可信处理。
适合:给编码助手接一个"执行工具"、内部跑用户提交的脚本、数据处理任务里执行不可信表达式。不适合:需要 GPU 训练、需要直连内网数据库或专有硬件的场景——这些能力一旦放开,沙箱的意义就没了。
需要说明的是,MXC 面向 Windows,隔离底座是系统自带的沙箱能力。如果你的团队主力在 Linux,本文的策略设计(默认拒绝、一次性实例、配额、代理白名单、审计日志)同样成立,只是要换成 bubblewrap、nsjail、gVisor 这类工具,命令部分不通用。
环境与前置条件
- 操作系统:Windows 10 或 Windows 11 的专业版、企业版、教育版。家庭版是否支持以官方文档当前版本为准。
- CPU 与虚拟化:64 位处理器,支持并在 BIOS/UEFI 中开启 Intel VT-x 或 AMD-V,支持 SLAT(二级地址转换)。建议 4 核以上。
- 内存:宿主机 8 GB 起步,建议 16 GB。沙箱会预留一块独立内存,具体在策略里配置。
- 磁盘:SSD,系统盘留出足够空闲空间。沙箱会占用一份系统镜像的存储开销,按 10 GB 以上空闲比较稳妥。
- 权限:首次启用系统功能需要本机管理员权限,日常运行建议用普通账户。
- MXC:从官方仓库的发布页面获取,安装方式与版本要求以官方文档当前版本为准。不同版本的子命令名可能有差异,动手前先看一遍
mxc --help。 - 运行时:沙箱是全新环境,宿主装的 Python、Node 不会自动出现。需要提前决定是把运行时以只读方式映射进去,还是在沙箱启动脚本里安装。
分步骤部署
第 1 步:启用 Windows 沙盒功能
以管理员身份打开 PowerShell:
```powershell
Enable-WindowsOptionalFeature -Online -FeatureName "Containers-DisposableClientVM" -All
```
这条命令启用"Windows 沙盒"这个可选功能,它提供的是基于虚拟化的隔离边界,沙箱内的进程和宿主机内核不共享同一个执行环境。
成功标志:输出里出现 RestartNeeded : True(或 False),按提示重启。重启后在开始菜单搜索"Windows Sandbox"能找到入口,说明底座就绪。
第 2 步:安装 MXC 并确认命令结构
按官方文档的安装方式装好 MXC,然后:
```powershell
mxc --version
mxc --help
```
--version 有输出说明装上了。重点看 --help 里的子命令列表,把"校验策略""运行任务"这两个动作对应的子命令名记下来——下面示例里写作 mxc config validate 和 mxc run,实际名称以你本机 --help 输出为准。
第 3 步:写一份最小策略文件
策略是整个方案的核心:能力边界写在文件里,不交给模型决定。新建 C:\mxc\policy.json,内容形如:
```json
{
"name": "code-runner",
"filesystem": {
"readOnly": ["C:\\mxc\\input"],
"readWrite": ["C:\\mxc\\scratch"],
"deny": [
"C:\\Users\\你的用户名\\.ssh",
"C:\\Users\\你的用户名\\.aws",
"C:\\Users\\你的用户名\\AppData"
]
},
"network": { "enabled": false },
"resources": {
"memoryMB": 4096,
"cpuCount": 2,
"maxProcesses": 64,
"wallClockSeconds": 120
},
"ui": {
"clipboard": false,
"printer": false
}
}
```
字段名和层级以官方文档与 JSON Schema 为准,这里列的是需要覆盖的维度:文件系统白名单、网络开关、资源配额、外设重定向。设计原则只有一条——默认拒绝,用到什么开什么。
注意 deny 里的三个路径:SSH 私钥、云厂商凭据、AppData。多数"智能体读到了不该读的东西"都栽在这里。
第 4 步:校验策略
```powershell
mxc config validate C:\mxc\policy.json
```
这一步在解析 JSON 结构、检查字段合法性。成功输出类似 policy is valid 或返回码 0。字段拼错会被挡在这里,比运行到一半才失败好排查。
第 5 步:跑一次冒烟测试
```powershell
mxc run --policy C:\mxc\policy.json -- python -c "print('hello from sandbox')"
```
-- 之后是沙箱内要执行的命令。成功标志:宿主终端打印出 hello from sandbox,且 C:\mxc\scratch 之外没有任何新文件产生。
如果提示找不到 python,说明运行时没进沙箱,见第 3 步的前置准备。
第 6 步:在宿主侧加超时兜底
策略里的 wallClockSeconds 是软约束,宿主侧再加一层硬兜底更稳:
```powershell
$job = Start-Job {
mxc run --policy C:\mxc\policy.json -- python C:\mxc\input\task.py
}
if (-not (Wait-Job $job -Timeout 150)) {
Stop-Job $job
Write-Warning "任务超时,已强制结束"
}
Receive-Job $job
Remove-Job $job -Force
```
注意 Start-Job 里要用绝对路径,后台作业的工作目录和当前终端不一致。这层兜底能挡住"沙箱进程自己没死、但任务卡住"的情况。
第 7 步:接一个执行工具给编码智能体
给智能体暴露一个函数,函数内部固定调用沙箱,参数只允许传代码:
```python
import subprocess, uuid, shutil, pathlib
POLICY = pathlib.Path(r"C:\mxc\policy.json")
SCRATCH = pathlib.Path(r"C:\mxc\scratch")
def run_code(code: str, timeout: int = 120) -> dict:
job_id = uuid.uuid4().hex
work = SCRATCH / job_id
work.mkdir(parents=True, exist_ok=True)
(work / "main.py").write_text(code, encoding="utf-8")
try:
p = subprocess.run(
["mxc", "run", "--policy", str(POLICY), "--",
"python", str(work / "main.py")],
capture_output=True, text=True, timeout=timeout,
)
return {"exit": p.returncode,
"stdout": p.stdout[-4000:],
"stderr": p.stderr[-4000:]}
except subprocess.TimeoutExpired:
return {"exit": 124, "stdout": "", "stderr": "timeout"}
finally:
shutil.rmtree(work, ignore_errors=True)
```
三个关键设计:策略路径写死在代码里,模型无法传入或覆盖;每次运行一个独立 job 目录,跑完就删;输出截断到 4000 字符,避免无限循环的输出把模型上下文灌爆。退出码和 stderr 一起回传,模型才能根据报错自我修正。
第 8 步:逃逸防护清单逐条落实
- 每个任务新建沙箱、用完销毁,不复用实例、不共享状态;
- 只映射必要的输入目录(只读)和输出目录(可写),其余一律不映射;
- 关闭剪贴板、打印机、COM 口重定向;无图形需求时关闭 vGPU 共享;
- 不把宿主的环境变量密钥透传进沙箱,需要凭据时用短期一次性令牌;
- 不把 Docker socket、SSH agent 挂进沙箱;
- 联网默认为关。确需联网时,让沙箱走宿主上的正向代理,代理侧做域名白名单并记日志;
- 沙箱产出的文件、日志、代码,回流到宿主后当作不可信内容处理,必要时再过一遍静态检查。
验证部署是否成功
按顺序跑一遍,全部通过才算搭好:
1. mxc --version 有输出,mxc config validate C:\mxc\policy.json 返回成功。
2. 功能验证:python -c "print(1+1)" 在沙箱内返回 2。
3. 网络隔离验证:沙箱内执行 python -c "import socket; socket.gethostbyname('example.com')",应当报解析失败或连接超时。能解析出 IP 说明网络没关干净。
4. 写保护验证:在 C:\mxc\input 放一个 a.txt,在沙箱内执行写入 C:\mxc\input\a.txt,应当返回"拒绝访问";退出后检查宿主上该文件内容未变。
5. 超时验证:沙箱内跑 python -c "while True: pass",应在约 120 秒后被终止,宿主进程列表无残留(可用 Get-Process | Where-Object { $_.ProcessName -like "*Sandbox*" } 检查)。
6. 内存限额验证:沙箱内申请远超 memoryMB 的内存(例如 8 GB 的字节数组),应被终止或抛出分配失败,而不是把宿主机拖到卡死。
常见报错与解决
报错:Windows Sandbox failed to start / 沙盒窗口闪一下就消失
→ 原因:虚拟化未在 BIOS 开启,或虚拟机监控程序平台未启用。
→ 解决:
```powershell
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -All
bcdedit /set hypervisorlaunchtype auto
```
执行后重启,再进 BIOS 确认 VT-x / AMD-V 已打开。
报错:Enable-WindowsOptionalFeature : 功能名称 Containers-DisposableClientVM 未知
→ 原因:当前系统版本不包含 Windows 沙盒功能。
→ 解决:先确认版本:
```powershell
Get-WindowsEdition -Online
```
若为家庭版,按官方文档确认支持情况;确实不支持时,改用独立虚拟机或云端一次性实例承载执行环境,策略设计照搬本文第 3 步和第 8 步。
报错:沙箱内 python: command not found 或 'node' 不是内部或外部命令
→ 原因:沙箱是干净环境,宿主机已装的运行时不会同步进去。
→ 解决:把运行时目录以只读方式加进策略的 readOnly 列表,或在沙箱初始化脚本里安装。例如把宿主机 Python 目录映射为只读,然后在沙箱内用绝对路径调用。
报错:写入映射目录时提示"拒绝访问"
→ 原因:该目录被配置为只读,这是预期行为,不是故障。
→ 解决:把需要写出的结果改写到 readWrite 目录:
```json
"filesystem": {
"readOnly": ["C:\\mxc\\input"],
"readWrite": ["C:\\mxc\\scratch"]
}
```
报错:policy validation failed: unknown field "xxx"
→ 原因:策略里用了当前版本不认识的字段名,或拼写错误。
→ 解决:先用只含 filesystem 和 network 的最小策略跑通,再逐个加字段。对照官方 JSON Schema 逐个核对键名,不要凭印象写。
现象:任务长时间不返回,宿主 CPU 占满
→ 原因:代码里有死循环或 fork 型进程爆炸,缺少超时和进程数限制。
→ 解决:策略里补上 maxProcesses 和 wallClockSeconds,宿主侧再加第 6 步的 Wait-Job -Timeout 硬兜底。
后续维护
备份:沙箱是无状态的,真正需要备份的是三样东西——策略文件(纳入 Git 管理,改动用 PR 审)、沙箱初始化脚本、输入输出目录。策略文件建议记录每次运行的哈希值,方便事后追溯"当时开的是哪些权限"。
升级:MXC 与 Windows 版本有耦合,升级任一者之前,先在测试机把上面 6 条验证清单完整跑一遍,尤其注意网络隔离和写保护两条。Windows 累积更新后也建议复跑。
日志:宿主侧至少记录每次运行的 job id、策略哈希、退出码、耗时、峰值内存;沙箱内日志落到 scratch 目录后归档。不要把输入里的敏感内容整体写进日志。
监控与清理:定期看 scratch 目录的增长速度、超时率、失败率。若发现残留的沙箱实例或孤儿 job 目录,加一条定时清理任务。readWrite 目录每季度过一遍,确认每个目录仍然必要——权限只会越长越多,需要有人主动收。
安全跟进:关注官方仓库的安全公告。隔离边界越高,能被绕过的攻击面越小;沙箱的价值取决于策略是否真的"默认拒绝",而这一点,靠的是每次加权限时多问一句"这个真的需要吗"。
