162 lines
8.4 KiB
Markdown
162 lines
8.4 KiB
Markdown
# NanoClaw 安全模型
|
||
|
||
## 信任模型
|
||
|
||
| 实体 | 信任级别 | 理由 |
|
||
|--------|-------------|-----------|
|
||
| 主群组(Main group) | 受信任 | 私人自我聊天,管理员控制 |
|
||
| 非主群组(Non-main groups) | 不受信任 | 其他用户可能是恶意的 |
|
||
| 容器 agent(Container agents) | 沙箱化 | 隔离的执行环境 |
|
||
| 入站消息(Incoming messages) | 用户输入 | 潜在的 prompt 注入 |
|
||
|
||
## 安全边界
|
||
|
||
### 1. 容器隔离(主要边界)
|
||
|
||
Agent 在容器(轻量级 Linux VM)中执行,提供:
|
||
- **进程隔离** - 容器进程无法影响宿主机
|
||
- **文件系统隔离** - 只有显式挂载的目录可见
|
||
- **非 root 执行** - 以非特权 `node` 用户(uid 1000)运行
|
||
- **临时容器** - 每次调用都是全新环境(`--rm`)
|
||
|
||
这是主要的安全边界。不是依赖应用级权限检查,而是通过限制挂载的内容来缩小攻击面。
|
||
|
||
### 2. 挂载安全
|
||
|
||
**外部白名单** - 挂载权限存储在 `~/.config/nanoclaw/mount-allowlist.json`,该文件:
|
||
- 位于项目根目录之外
|
||
- 永远不会挂载到容器中
|
||
- 无法被 agent 修改
|
||
|
||
**默认阻止模式:**
|
||
```
|
||
.ssh, .gnupg, .aws, .azure, .gcloud, .kube, .docker,
|
||
credentials, .env, .netrc, .npmrc, id_rsa, id_ed25519,
|
||
private_key, .secret
|
||
```
|
||
|
||
**保护措施:**
|
||
- 验证前解析符号链接(防止目录遍历攻击)
|
||
- 容器路径验证(拒绝 `..` 和绝对路径)
|
||
- `nonMainReadOnly` 选项强制非主群组使用只读
|
||
|
||
**只读项目根目录:**
|
||
|
||
主群组的项目根目录以只读方式挂载。Agent 需要的可写路径(store、群组目录、IPC、`.claude/`)单独挂载。这防止 agent 修改宿主机应用代码(`src/`、`dist/`、`package.json` 等),否则下次重启时整个沙箱将被完全绕过。`store/` 目录以读写方式挂载,以便主 agent 可以直接访问 SQLite 数据库。
|
||
|
||
### 3. Session 隔离
|
||
|
||
每个群组在 `data/sessions/{group}/.claude/` 拥有隔离的 Claude session:
|
||
- 群组无法查看其他群组的对话历史
|
||
- Session 数据包含完整的消息历史和已读取的文件内容
|
||
- 防止跨群组信息泄露
|
||
|
||
### 4. IPC 授权
|
||
|
||
消息和任务操作根据群组身份进行验证:
|
||
|
||
| 操作 | 主群组 | 非主群组 |
|
||
|-----------|------------|----------------|
|
||
| 向自己的聊天发送消息 | ✓ | ✓ |
|
||
| 向其他聊天发送消息 | ✓ | ✗ |
|
||
| 为自己安排定时任务 | ✓ | ✓ |
|
||
| 为其他群组安排定时任务 | ✓ | ✗ |
|
||
| 查看所有任务 | ✓ | 仅自己的 |
|
||
| 管理其他群组 | ✓ | ✗ |
|
||
|
||
### 5. 凭证隔离(OneCLI Agent Vault)
|
||
|
||
真实的 API 凭证**永远不会进入容器**。NanoClaw 使用 [OneCLI 的 Agent Vault](https://github.com/onecli/onecli) 来代理出站请求并在网关层面注入凭证。
|
||
|
||
**工作原理:**
|
||
1. 凭证通过 `onecli secrets create` 一次性注册,由 OneCLI 存储和管理
|
||
2. 当 NanoClaw 启动容器时,调用 `applyContainerConfig()` 将出站 HTTPS 路由通过 OneCLI 网关
|
||
3. 网关按 host 和 path 匹配请求,注入真实凭证并转发
|
||
4. Agent 无法发现真实凭证——不在环境变量、stdin、文件或 `/proc` 中
|
||
|
||
**按 agent 策略:**
|
||
每个 NanoClaw 群组拥有自己的 OneCLI agent 身份。这允许按群组设置不同的凭证策略(例如,销售 agent vs. 支持 agent)。OneCLI 支持速率限制,基于时间的访问和审批流程正在规划中。
|
||
|
||
**不挂载的内容:**
|
||
- 渠道认证 session(`store/auth/`)——仅宿主机
|
||
- 挂载白名单——外部存储,永不挂载
|
||
- 任何匹配阻止模式的凭证
|
||
- `.env` 在项目根目录挂载中被 `/dev/null` 遮蔽
|
||
|
||
## 权限对比
|
||
|
||
| 能力 | 主群组 | 非主群组 |
|
||
|------------|------------|----------------|
|
||
| 项目根目录访问 | `/workspace/project`(只读) | 无 |
|
||
| Store(SQLite DB) | `/workspace/project/store`(读写) | 无 |
|
||
| 群组目录 | `/workspace/group`(读写) | `/workspace/group`(读写) |
|
||
| 全局记忆 | 通过项目隐式访问 | `/workspace/global`(只读) |
|
||
| 额外挂载 | 可配置 | 只读,除非允许 |
|
||
| 网络访问 | 无限制 | 无限制 |
|
||
| MCP 工具 | 全部 | 全部 |
|
||
|
||
## 安全架构图
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 不受信任区域(UNTRUSTED ZONE) │
|
||
│ 入站消息(潜在恶意) │
|
||
└────────────────────────────────┬─────────────────────────────────┘
|
||
│
|
||
▼ 触发检查、输入转义
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 宿主机进程(HOST PROCESS,受信任) │
|
||
│ • 消息路由 │
|
||
│ • IPC 授权 │
|
||
│ • 挂载验证(外部白名单) │
|
||
│ • 容器生命周期 │
|
||
│ • OneCLI Agent Vault(注入凭证,执行策略) │
|
||
└────────────────────────────────┬─────────────────────────────────┘
|
||
│
|
||
▼ 仅显式挂载,无 secrets
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ 容器(CONTAINER,隔离/沙箱化) │
|
||
│ • Agent 执行 │
|
||
│ • Bash 命令(沙箱内) │
|
||
│ • 文件操作(限于挂载范围) │
|
||
│ • API 调用通过 OneCLI Agent Vault 路由 │
|
||
│ • 环境变量或文件系统中无真实凭证 │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 供应链安全(pnpm)
|
||
|
||
NanoClaw 使用 pnpm,在 `pnpm-workspace.yaml` 中配置了两道供应链防护:
|
||
|
||
### 最低发布龄期
|
||
|
||
`minimumReleaseAge: 4320`(3 天)。pnpm 将拒绝解析发布不到 3 天的任何包版本。这可以防御仿冒包和被盗用的维护者账户——大多数恶意发布在 72 小时内会被检测并撤回。
|
||
|
||
**将包排除在发布龄期门禁之外**(`minimumReleaseAgeExclude`):
|
||
|
||
这种情况应很少发生。当零日修复或关键依赖需要立即更新时:
|
||
|
||
1. 排除条目必须经人类维护者审查和批准
|
||
2. 条目必须锁定被排除的**确切版本**——绝不能使用范围或通配符
|
||
```yaml
|
||
minimumReleaseAgeExclude:
|
||
some-package: "1.2.3" # 由 @user 批准, 2026-04-14 — CVE-XXXX-YYYY 修复
|
||
```
|
||
3. 一旦该版本超过阈值(即 3 天后),应移除排除项
|
||
4. 自动化 agent(Claude、CI 机器人)绝不能在没有人类签署的情况下添加排除项
|
||
|
||
### 构建脚本白名单
|
||
|
||
`onlyBuiltDependencies` 限制哪些包可以执行 install/postinstall 脚本。只有此列表中的包才被允许在 `pnpm install` 期间运行构建脚本。当前允许的包:
|
||
|
||
- `better-sqlite3` — 编译原生 SQLite 绑定
|
||
- `esbuild` — 下载平台特定的二进制文件
|
||
- `protobufjs` — 生成 protobuf 绑定(Baileys/libsignal 使用)
|
||
- `sharp` — 下载平台特定的图像处理二进制文件
|
||
|
||
向此列表添加包需要人类批准——构建脚本以安装用户的权限执行任意代码。
|
||
|
||
### `.npmrc` 安全网
|
||
|
||
`.npmrc` 文件包含 `minReleaseAge=3d` 作为后备。权威设置在 `pnpm-workspace.yaml` 中,但如果 npm 曾被直接调用(例如被不遵循 pnpm 的工具调用),`.npmrc` 提供纵深防御。
|