# 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` 提供纵深防御。