> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 为你的AI代理构建安全沙箱
- URL: https://www.hubwiz.com/blog/build-a-secure-sandbox-for-your-ai-agent/
- Published: 2026-02-01T23:46:30.000Z
- Updated: 2026-02-01T23:46:30.000Z
- Description: 在本指南中，我将向你展示如何使用 Docker 和 Node.js 为本地开发构建一个沙盒命令运行器。它将为你的代理提供读/写工作空间和互联网访问——但只能访问你明确允许的特定域。
- Author: admin
- Tags: AGENT, SANDBOX, #Import 2026-10-14 14:41

批准疲劳是安全性的敌人。学习为你的 AI 代理构建一个安全 Docker 沙箱，它消除了不断的权限提示。

如果你最近使用过任何代理编码工具，你知道套路。代理想要运行 `npm install`。你收到提示：*允许命令？* 然后它想要运行测试。*允许命令？* 然后它需要调试失败。*允许命令？*

到第十个提示时，你不再审核安全性。你只是在训练自己点击"是"，好让你回到工作。这被称为**批准疲劳**，它是安全性的敌人。

解决方案不是让代理问更好听的问题。解决方案是将代理放在一个它不需要问的盒子里。

在本指南中，我将向你展示如何使用 Docker 和 Node.js 为本地开发构建一个**沙盒命令运行器**。它将为你的代理提供读/写工作空间和互联网访问——但只能访问你明确允许的特定域。

## 1、架构

我们不仅仅是在运行容器；我们在构建一个受控环境。我们的系统有两层防御：

- **文件系统监狱（Docker）：** 代理看到一个只读操作系统。它唯一可以写入的地方是我们挂载的特定项目目录。它无法触碰你的 SSH 密钥、其他文件夹中的 `.env` 文件或你的系统配置。
- **网络门卫（Node.js 代理）：** 我们不仅仅给容器开放互联网。我们强制流量通过本地代理，该代理根据允许列表检查每个请求。

![](https://www.hubwiz.com/blog/content/images/2026/01/image-665.png)

## 2、门卫（代理）

首先，我们需要一个代理。Docker 的原生网络控制是基于 IP 的，当你只想说"允许 `registry.npmjs.org`"时，这很烦人。

我们将构建一个最小化的 Node.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`）。这是你的防火墙。

## 3、监狱（容器）

现在我们需要环境。我们不仅仅是在运行 `docker run ubuntu`。我们在锁定它。

以下是我们想要的配置：

**只读根：** 代理无法修改操作系统文件。

- **Tmpfs：** 给它一个 `/tmp` 中的草稿本，当容器死亡时消失。
- **用户映射：** 以非根用户运行，所以创建的文件由*你*拥有，而不是 `root`。
- **网络配置：** 注入指向我们主机机器的 `HTTP_PROXY` 变量。

以下是概念性的 Docker 命令（我们将在第3部分将其包装在脚本中）：

```
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 上的本地开发，这是让容器看到 `localhost:8888`（我们的代理）的最简单方法。在 macOS/Windows 上，你会使用 `--network bridge` 并将代理指向 `host.docker.internal:8888`。

## 4、运行器

让我们将它们组合成一个简单的运行器脚本。这是你的代理会调用的，而不是 `exec()`。

创建 `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}`);
});

```

## 5、让我们测试它

1. **启动代理** 在一个终端中：

```
node proxy.js

```

**2\. 尝试禁止请求**（Google）：

```
node sandbox-runner.js "curl -I https://google.com"

```

*结果：* 命令立即失败。代理记录：`[BLOCKED] CONNECT request to google.com`。

**3\. 尝试允许请求**（GitHub）：

```
node sandbox-runner.js "curl -I https://github.com"

```

*结果：* 成功。`HTTP/1.1 200 Connection Established`。

**4\. 尝试删除操作系统**：

```
node sandbox-runner.js "rm -rf /bin"

```

*结果：* `rm: cannot remove '/bin': Read-only file system`。

## 6、为什么这很重要

我们从根本上改变了安全模型。

**之前：**

- 安全依赖于**过程**。（你阅读命令。）
- 失败模式：你累了，点击"是"，代理将你的 `.env` 文件上传到 pastebin。

**之后：**

- 安全依赖于**架构**。（网络拓扑。）
- 失败模式：代理尝试上传你的 `.env` 文件，代理看到 `pastebin.com` 不在列表中，连接被丢弃。你甚至不需要在那里。

这允许你为沙箱给代理"自动批准"模式。你信任*盒子*，而不是*机器人*。

## 7、已知的限制

这种方法是健壮的，但它不是魔法。

- **Docker Socket：** 永远不要将 `/var/run/docker.sock` 挂载到这个沙箱中。如果你这样做，代理可以生成一个新的特权容器并立即逃逸。
- **出口旁路：** 我们依赖 `HTTP_PROXY` 环境变量。一个真正恶意的二进制文件可以忽略这些变量并尝试直接连接到 IP。在企业环境中，你会在防火墙级别阻止非代理出口。对于本地开发，这阻止了意外外泄和 99% 的"供应链"攻击（通常使用标准 HTTP 库）。
- **性能：** 为每个命令启动容器有开销。对于"与代码库聊天"循环，它可以忽略。对于紧密的"编辑-运行-测试"循环，你可能希望在后台保持容器运行。

## 8、结束语

代理正在变得足够强大以变得危险。我们不应该用权限提示来削弱它们；我们应该为它们构建操场，让它们快速运行并安全地破坏东西。

从这个 `proxy.js` 和 `docker run` 设置开始。这是 50 行代码，可能让你免于非常糟糕的一天。

---

原文连接：[Build a Secure Sandbox for Your AI Agent](https://pub.towardsai.net/build-a-secure-sandbox-for-your-ai-agent-dd67185e4761?ref=hubwiz.com)

汇智网翻译整理，转载请标明出处