别再点“允许”了:真正安全的AI Agent沙盒,应该像监狱一样狠
全栈AI·探索:涵盖动效、React Hooks、Vue 技巧、LLM 应用、Python 脚本等专栏,案例驱动实战学习,点击二维码了解更多详情。原因很简单: 在 Linux 上,host 模式最省事,容器可以直接访问 localhost:8888。只要它说“为了修复 bug”,我就点允许。如果 Agent 运行某些恶意二进制,完全可以无视这些变量,直接连 IP。你只需要相信“笼子”,而不是相信“
你有没有发现一件很可怕的事:AI Agent 越聪明,你越容易变蠢。
因为它会不断问你:
-
“我要执行 npm install,可以吗?”
-
“我要跑测试,可以吗?”
-
“我要调试错误,可以吗?”
-
“我要 curl 一个地址,可以吗?”
你一开始还认真看。 到第十次,你已经不看了——手比脑子快,直接点 Yes。
这不是你懒。 这是人类的大脑被系统训练出来的审批疲劳(approval fatigue)。
而审批疲劳,就是安全的天敌。
所以真正的解决方案不是让 AI “问得更礼貌”,而是——让它根本没必要问。
把它关进一个盒子里。 一个它想作死也作不出去的盒子。
今天我就带你搭一个:给 AI Agent 用的 Docker 安全沙盒 + 网络代理防火墙。
它能做到:
-
允许读写你的项目目录
-
允许联网
-
但联网只能访问你允许的域名
-
容器系统本身只读,删不掉 /bin
-
就算 Agent 想偷你的 .env,也发不出去
你不需要再不断弹窗批准。 你只需要相信“笼子”,而不是相信“机器人”。
一、整体架构:别给 Agent 自由,给它规则
我们要的不是一个普通容器。 我们要的是一个“可控环境”。
整个系统有两道防线:
1)文件系统监狱(Docker)
容器内部看到的是一个只读的操作系统。
它能写的地方只有:
-
你挂载进去的项目目录(比如 /workspace)
-
临时目录 /tmp(用 tmpfs,容器死了就清空)
它想碰你电脑里的东西? 对不起,根本看不见。
-
SSH Key?看不到
-
你别的目录里的 .env?碰不到
-
系统配置文件?动不了
一句话:它只能在你允许的文件夹里“折腾”。
2)网络门卫(Node.js Proxy)
更狠的来了。
我们不直接给容器开“全网通”。 我们让它所有网络请求都必须经过一个代理。
这个代理做的事很简单:
-
请求域名在白名单 → 放行
-
不在白名单 → 直接掐断
这就像机场安检: 你可以飞,但你不能带炸弹。
二、第一部分:写一个网络“门卫”(Proxy)
Docker 自带网络控制,但它是按 IP 控的。 问题是你真正想管的是域名,比如:
-
registry.npmjs.org
-
github.com
所以我们自己写个极简 Node.js 代理。
创建 proxy.js
新建文件 proxy.js:
const http = require('http');
const net = require('net');
const url = require('url');
// 1. The Policy
const ALLOWED_DOMAINS = [
'registry.npmjs.org', // For installing packages
'github.com', // For cloning repos
'api.openai.com' // If the agent needs to talk to the LLM from inside
];
const PORT = 8888;
const server = http.createServer((req, res) => {
// Handle standard HTTP requests (less common now, but good to have)
const parsed = url.parse(req.url);
if (!isAllowed(parsed.hostname)) {
res.writeHead(403);
res.end('Blocked by Sandbox Proxy');
console.log(`[BLOCKED] HTTP request to ${parsed.hostname}`);
return;
}
// ... (HTTP forwarding logic would go here, omitting for brevity/HTTPS focus)
});
// 2. Handle HTTPS (The CONNECT method)
server.on('connect', (req, clientSocket, head) => {
const { port, hostname } = url.parse(`//${req.url}`, false, true);
if (!isAllowed(hostname)) {
console.log(`[BLOCKED] CONNECT request to ${hostname}`);
clientSocket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
clientSocket.end();
return;
}
console.log(`[ALLOWED] ${hostname}`);
// 3. The Pipe
const serverSocket = net.connect(port || 443, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
serverSocket.on('error', (err) => {
console.error(`[ERROR] Connection to ${hostname} failed:`, err.message);
clientSocket.end();
});
});
function isAllowed(hostname) {
// Simple substring match to allow subdomains (e.g., sub.github.com)
return ALLOWED_DOMAINS.some(d => hostname === d || hostname.endsWith(`.${d}`));
}
server.listen(PORT, () => {
console.log(`🛡️ Sandbox Proxy running on port ${PORT}`);
});
启动代理
终端运行:
node proxy.js
这玩意儿就是你的“网络防火墙”。
从此以后,容器里的 AI 想联网? 先过我这一关。
三、第二部分:把 Agent 关进 Docker “牢房”
现在开始搭“监狱”。
我们的目标配置是:
-
根目录只读(--read-only)
-
/tmp 用 tmpfs 临时存储
-
容器里用普通用户运行,别用 root
-
强制走 HTTP_PROXY / HTTPS_PROXY
-
只挂载当前目录,不给它全盘权限
概念 Docker 命令(先看效果)
docker run \
--rm \
--user $(id -u):$(id -g) \
--read-only \
--tmpfs /tmp \
--network host \
-v $(pwd):/workspace \
-w /workspace \
-e HTTP_PROXY=http://localhost:8888 \
-e HTTPS_PROXY=http://localhost:8888 \
node:18-slim \
npm install
看到这里你可能会皱眉:为什么用 --network host?
原因很简单: 在 Linux 上,host 模式最省事,容器可以直接访问 localhost:8888。
如果你是 macOS 或 Windows: host 网络模式不一样,你得改成 bridge,然后代理地址写:
host.docker.internal:8888
四、第三部分:写一个“沙盒执行器”(Runner)
我们要做的,是让 AI Agent 不再直接 exec()。 它只允许调用这个 runner。
你可以理解为:
AI 想执行命令? 可以。 但只能通过“狱警”执行。
创建 sandbox-runner.js
新建 sandbox-runner.js:
const { spawn } = require('child_process');
const os = require('os');
const commandToRun = process.argv[2] || 'echo "No command provided"';
const isMac = os.platform() === 'darwin';
// Configure network for Mac vs Linux
const networkFlag = isMac ? [] : ['--network', 'host'];
const proxyHost = isMac ? 'host.docker.internal' : 'localhost';
const proxyUrl = `http://${proxyHost}:8888`;
const dockerArgs = [
'run',
'--rm', // Cleanup after run
'--read-only', // Immutable OS
'--tmpfs', '/tmp', // Writable temp space
'--tmpfs', '/run', // Needed for some tools
'-v', `${process.cwd()}:/workspace`, // Mount current dir ONLY
'-w', '/workspace', // Set working dir
'-e', `HTTP_PROXY=${proxyUrl}`, // Force traffic to proxy
'-e', `HTTPS_PROXY=${proxyUrl}`,
'-e', 'NPM_CONFIG_REGISTRY=http://registry.npmjs.org/', // Force non-SSL for easier proxying, or allow HTTPS registry
...networkFlag,
'node:18-slim', // Image to use
'/bin/sh', '-c', commandToRun
];
console.log(`📦 Sandboxing: "${commandToRun}"`);
const child = spawn('docker', dockerArgs, { stdio: 'inherit' });
child.on('close', (code) => {
console.log(`\nEnd of sandbox session. Exit code: ${code}`);
});
现在你的 Agent 执行任何命令,只需要调用:
node sandbox-runner.js "npm install"
就行。
五、开始测试:让它试试“越狱”
先开代理:
node proxy.js
然后新开一个终端。
1)测试禁止访问:Google
node sandbox-runner.js "curl -I https://google.com"
结果:直接失败。 代理会输出:
[BLOCKED] CONNECT request to google.com
爽不爽? 这才叫控制权。
2)测试允许访问:GitHub
node sandbox-runner.js "curl -I https://github.com"
结果成功。
你会看到:
HTTP/1.1 200 Connection Established
3)测试删除系统文件
node sandbox-runner.js "rm -rf /bin"
结果是:
rm: cannot remove '/bin': Read-only file system
容器系统是只读的,它连“自残”都做不到。
六、为什么这套东西意义巨大?
因为它改变了安全模型。
以前的安全是什么?
以前的安全靠的是:流程。
AI 每执行一步,你都要看一眼。
理论上你应该认真审查。 但现实是——你迟早会累。
累了之后你就会进入一种状态:
只要不是 rm -rf /,我就点允许。 只要它说“为了修复 bug”,我就点允许。
然后有一天,它顺手把你的 .env 上传到了某个地址。 你连发现都来不及。
现在的安全是什么?
现在的安全靠的是:架构。
你不需要一直盯着 AI。 你只需要盯着“规则”。
AI 想把 .env 发到 pastebin?
对不起:
-
pastebin.com 不在白名单
-
网络请求被代理掐断
-
它上传不了
你甚至可以不在电脑前。 它也出不了事。
这就叫:信任盒子,不信任机器人。
七、局限性
这套方案很强,但不是“绝对安全”。
它能挡住 99% 的现实事故,但不是核弹级防御。
1)Docker Socket 是绝对禁区
永远别挂载:
/var/run/docker.sock
一旦挂载进去,Agent 就能自己启动一个特权容器。 然后越狱成功。
一句话:你等于把监狱钥匙递给犯人。
2)代理规则靠环境变量,有绕开的可能
我们靠的是:
-
HTTP_PROXY
-
HTTPS_PROXY
如果 Agent 运行某些恶意二进制,完全可以无视这些变量,直接连 IP。
企业环境里通常会用防火墙阻断非代理流量。 本地开发环境里,这套方案主要防:
-
误操作泄露
-
供应链攻击(npm install 拉恶意包)
-
Agent “顺手”上传敏感文件
3)性能开销
每次执行命令都要起一个容器,肯定有成本。
但对于“对话式写代码”来说,这点开销可以忽略。 如果你要极限跑测试循环,那可以把容器常驻。
八、最终结论:别让 Agent 变成你最大的安全漏洞
AI Agent 越来越强。 强到你给它权限,它真的敢乱来。
你要做的不是让它更听话, 而是让它在可控的范围里“撒野”。
你应该给它一个游乐场,而不是把整个家交给它。
你只需要三样东西:
-
proxy.js:网络门卫
-
docker read-only sandbox:文件系统牢房
-
sandbox-runner.js:统一执行入口
总共加起来也就几十行代码。
但它能帮你避免某个深夜里:
你点了第 11 次“允许” 然后第二天醒来发现密钥全没了。
如果你愿意,我还可以继续帮你把这篇文章再升级成更“咪蒙风”的版本,比如:
-
更强的情绪钩子
-
更像朋友圈爆款的节奏
-
更多反问句、短句、狠句
-
开头直接抓人那种
全栈AI·探索:涵盖动效、React Hooks、Vue 技巧、LLM 应用、Python 脚本等专栏,案例驱动实战学习,点击二维码了解更多详情。

最后:
更多推荐



所有评论(0)