- AI Agent
- 后端
- MCP 服务
- 浏览器控制
- Agent 评测
【免费下载链接】sandbox
All-in-One Sandbox for AI Agents that combines Browser, Shell, File, MCP and VSCode Server in a single Docker container.
导读
本文聚焦 AIO Sandbox(All-in-One Sandbox for AI Agents)在本地可信环境之外部署时的安全加固方案。默认情况下,沙盒面向可信本地开发使用;当需要暴露给网络或其他服务时,必须开启鉴权并收紧访问边界。读完本文,你将掌握:用JWT_PUBLIC_KEY启用 Bearer token 校验的完整流程、短时票据的换取与使用方式、反向代理与网络边界的最小暴露策略,以及密钥处理的最佳实践。
安全模型总览:默认可信,暴露需加固
AIO Sandbox 把浏览器、Shell、文件、MCP 与 VSCode Server 集成在同一个 Docker 容器中,其核心 API(如/v1/sandbox、/v1/shell/exec、/v1/file/read)能力非常强。默认情况下,沙盒面向可信本地开发使用,此时无需额外鉴权;但一旦要暴露给网络或其他服务,就必须补齐三个层面:
- 身份鉴权:启用 JWT Bearer token 校验或共享 token,确保只有持有合法凭证的调用方可以访问 API;
- 访问边界:端口绑定、反向代理、IP/网络/服务身份限制,缩小暴露面;
- 凭据管理:密钥的注入方式与生命周期控制,避免长期密钥进入镜像或生成文件。
对应环境变量的完整说明见 环境变量配置 中的「安全」小节:
| 变量 | 默认值 | 用途 |
|---|---|---|
JWT_PUBLIC_KEY | 空 | 启用 API 和 Web 路由的 Bearer token 校验 |
AUTH_TOKEN | 空 | 简单部署场景的共享 token,取决于运行镜像是否支持 |
JWT 鉴权:用公钥验证 Bearer Token
原理与角色划分
设置JWT_PUBLIC_KEY即可启用 Bearer token 校验,采用典型的非对称签名模式:
- 业务侧(Token 签发方):使用私钥签发 JWT;
- 沙盒侧(Token 验证方):只持有 base64 编码的公钥,通过
JWT_PUBLIC_KEY环境变量注入,验证每个请求携带的 Bearer token。
这种公私钥分离的设计保证私钥不会进入沙盒镜像,业务侧可以独立控制签发策略(如有效期、受众),沙盒侧只负责验证。
生成密钥对
使用 OpenSSL 生成 2048 位 RSA 密钥对:
openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pemprivate_key.pem保留在业务侧,public_key.pem用于注入沙盒。
启动沙盒并注入公钥
通过-e JWT_PUBLIC_KEY="$(base64 -w 0 public_key.pem)"把公钥(base64 单行编码)注入容器。同时建议把端口只绑定到 localhost,避免沙盒 API 直接暴露到局域网或公网:
docker run --security-opt seccomp=unconfined --rm -it \ -p 127.0.0.1:8080:8080 \ -e JWT_PUBLIC_KEY="$(base64 -w 0 public_key.pem)" \ ghcr.io/agent-infra/sandbox:latest说明:
--security-opt seccomp=unconfined是 AIO Sandbox 运行的必要参数(浏览器等组件依赖),与鉴权无关但不可省略。镜像名以当前仓库 docker-compose.yaml 与 README.md 中使用的ghcr.io/agent-infra/sandbox:latest为准。
使用 Docker Compose 时,仓库的 docker-compose.yaml 已预留了端口绑定与环境变量透传:
ports: - "127.0.0.1:${HOST_PORT:-8080}:8080" environment: JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY:-}也就是说,你只需在宿主机导出JWT_PUBLIC_KEY环境变量(或.env文件),Compose 会自动注入容器。
业务侧签发 JWT 并调用 API
业务服务用私钥签发 token(有效期建议按需控制,例如 1 小时),然后调用 API 时携带 Bearer token:
curl "http://localhost:8080/v1/sandbox" \ -H "Authorization: Bearer $SANDBOX_TOKEN"在本地验证鉴权链路的完整流程(从密钥生成到请求成功),可参考 鉴权指南,其中包含用 shell 直接构造 RS256 JWT 的脚本:
base64url_encode() { openssl base64 -e -A | tr '+/' '-_' | tr -d '='; } header='{"alg":"RS256","typ":"JWT"}' exp_time=$(($(date +%s) + 3600)) payload="{\"exp\":${exp_time}}" to_be_signed="$(echo -n "$header" | base64url_encode).$(echo -n "$payload" | base64url_encode)" signature=$(echo -n "$to_be_signed" | openssl dgst -sha256 -sign private_key.pem | base64url_encode) jwt="${to_be_signed}.${signature}"并可通过curl "http://localhost:8080/cdp/json/version" -H "Authorization: Bearer ${jwt}"验证带鉴权的浏览器调试端点。生产环境中应使用成熟 JWT 库签发,而不是手写脚本。
共享 token 的补充场景
对于简单部署场景,镜像若支持还可以通过AUTH_TOKEN环境变量启用共享 token 鉴权(见 环境变量配置)。它不依赖密钥对,适合单点信任的内网场景;但共享 token 无法做细粒度的签发与吊销控制,因此安全要求较高时仍应优先使用 JWT 模式。
短时票据:为浏览器访问与临时交接而设计
为什么需要票据
JWT 需要放在Authorization请求头中,但浏览器直接打开 VNC、WebSocket 等页面时无法自定义请求头。此时就用「短时票据」替代:先携带 JWT 通过一次带鉴权的 API 调用换取一次性票据,再把票据以 URL 查询参数(?ticket=...)形式拼接到前端访问地址中。
票据应尽快过期,并限制在最小必要访问范围内(例如只允许访问 VNC 对应路径),从而把长期 JWT 的泄露风险收敛为一个几十秒内有效的临时凭证。
端点与 SDK 佐证
从 SDK 源码可以看出票据功能的官方实现(sdk/python/agent_sandbox/auth/raw_client.py):
POST /tickets:创建并返回一个短时票据。SDK 文档明确标注这是非幂等操作,每次调用都会生成一个新的唯一票据(见 sdk/python/agent_sandbox/auth/client.py);GET /auth:验证请求,支持两种凭证——x-original-uri请求头中的票据,或Authorization请求头中的 JWT。该端点专为 Nginxauth_request之类的鉴权子请求设计(见 sdk/python/agent_sandbox/auth/raw_client.py)。
Python SDK 中的调用方式:
from agent_sandbox import Sandbox client = Sandbox(base_url="http://localhost:8080") ticket = client.auth.create_ticket()完整换取与使用流程
前置条件:服务已通过静态(
JWT_PUBLIC_KEY)或动态模式启动并完成鉴权配置。用 JWT 换取票据:票据默认有效期为 30 秒,可通过
TICKET_TTL_SECONDS环境变量调整:
ticket_response=$(curl --silent -X POST "http://localhost:8080/tickets" \ -H "Authorization: Bearer ${jwt}") ticket=$(echo "$ticket_response" | jq -r .ticket) expires=$(echo "$ticket_response" | jq -r .expires_in) echo "票据: ${ticket}, 有效期: ${expires}秒"- 客户端拼接访问 URL(以 VNC 为例):
vnc_url="http://localhost:8080/vnc/index.html?ticket=${ticket}&path=websockify%3Fticket%3D${ticket}"浏览器打开该 URL 即可在无请求头能力的情况下完成鉴权访问。完整的可运行示例见 鉴权指南。
网络边界:最小暴露原则
无论是否开启鉴权,网络边界都是必须单独落实的一层:
- 不需要远程访问时,只绑定到 localhost。例如上文
-p 127.0.0.1:8080:8080,或 Compose 中的127.0.0.1:${HOST_PORT:-8080}:8080,让沙盒 API 只在本机可达; - 共享环境中,建议在沙盒前放置带 TLS 的反向代理。沙盒内部服务走 HTTP,TLS 终结放在代理层;同时可配合上文提到的
GET /auth端点做auth_request鉴权子请求,把「先鉴权、后转发」的职责交给代理; - 通过 IP、网络或服务身份限制入站访问。例如防火墙只放行内网网段、Kubernetes 下用 NetworkPolicy 限定来源 Pod(见 README.md 中的 Deployment 示例),云环境可用安全组;
- 不要把未鉴权的沙盒 API 暴露到公网。沙盒内的 Shell 与文件 API 具备完整执行能力,一旦裸奔暴露等同于把主机交给任意访客。
更完整的云端部署边界建议(边缘层加鉴权、启用沙盒自身 JWT 鉴权)可参考 云部署指南。
密钥处理:凭据的生命周期管理
针对可能进入沙盒容器的密钥,遵循以下原则:
- 通过运行时环境变量或密钥管理系统传入密钥。沙盒的配置体系本身就建立在环境变量之上,
JWT_PUBLIC_KEY、AUTH_TOKEN都应通过docker run -e或 Compose 的environment注入,而不是烧进镜像; - 不要把密钥写入自定义镜像。镜像会被复制、分发和长期留存,一旦打入镜像就失去吊销能力;
- 不要把长期密钥写入 Skills、Hooks、Notebook 或生成文件。这些内容可能在沙盒工作区持久化、被 Agent 读取或随上下文泄露,长期密钥一旦进入就等于明文外泄;
- 任务级访问优先使用短时凭据。单个任务用几十秒有效的票据或短有效期 JWT,即便被截获,其影响范围也随时间自动收敛。
小结:从本地可信到生产可用的安全 Checklist
| 层级 | 措施 | 关键配置/依据 |
|---|---|---|
| 身份鉴权 | 开启 JWT Bearer token 校验 | JWT_PUBLIC_KEY(base64 公钥),见 环境变量配置 |
| 身份鉴权 | 简单场景共享 token | AUTH_TOKEN |
| 临时交接 | 浏览器/WebSocket 访问用短时票据 | POST /tickets+?ticket=,TICKET_TTL_SECONDS控制有效期 |
| 网络边界 | 端口只绑 localhost、前置 TLS 反向代理、限制入站来源 | -p 127.0.0.1:8080:8080、GET /auth供代理auth_request使用 |
| 密钥管理 | 环境变量注入、不入镜像、不写进生成文件、优先短时凭据 | 见 docker-compose.yaml 环境变量示例 |
AIO Sandbox 的安全模型可以概括为一句话:默认面向可信本地,暴露即需鉴权。按照本文的 JWT 鉴权、短时票据、网络边界与密钥管理四步加固后,沙盒的 Browser、Shell、File 等全部能力才能在受控边界内安全地开放给 Agent 与其他服务使用。
- AI Agent
- 后端
- MCP 服务
- 浏览器控制
- Agent 评测
【免费下载链接】sandbox
All-in-One Sandbox for AI Agents that combines Browser, Shell, File, MCP and VSCode Server in a single Docker container.
相关推荐
MeTube 安全模型与漏洞披露指南:无鉴权 by design 的边界、防护与部署加固
MeTube 安全模型与漏洞披露指南:无鉴权 by design 的边界、防护与部署加固 MeTube 是一个自托管的视频下载服务(yt dlp 的 Web U
后端前端RVC语音变声完整指南:用10分钟语音数据训练专属AI音色的全流程实战
RVC语音变声完整指南:用10分钟语音数据训练专属AI音色的全流程实战 Retrieval based Voice Conversion WebUI(以下简称
人工智能AI 应用语音音频深度学习从一句话需求到规范文档:拆解 GPT-Pilot 的 Spec Writer
从一句话需求到规范文档:拆解 GPT Pilot 的 Spec Writer 凌晨一点半,产品第三次改口:这个功能"要保留,但要换个交互"。你翻出三天前的需求文
人工智能AI Agent代码智能体AI 应用开发工具CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考