AI 编程教程中文版
从原理到实战

09 · Channel 与安全:谁能进来、能做什么

从 OpenClaw 官方安全模型出发,拆清 Channel 路由、DM 配对、群组门控、工具权限、沙箱和 Gateway 暴露。

OpenClaw 的安全问题不能只问“模型聪不聪明”。真正要问的是三件事:

谁能触发 Agent?Agent 能调用哪些工具?这些工具在哪里运行?

这三件事分别落在 Channel access、Tool policy、Sandbox / Elevated 上。系统提示词和 prompt injection 防御只能降低风险,不能替代这些硬边界。

这一篇的核心判断:安全边界不在模型嘴上,而在 Gateway 入口、Session 隔离、Tool policy、Sandbox 和网络暴露面上。

flowchart LR
    Sender["外部发送者"] --> Access["Channel access<br/>谁能进来"]
    Access --> Route["Routing<br/>进哪个 Agent"]
    Route --> Context["Session / Context<br/>看到哪些上下文"]
    Context --> Policy["Tool policy<br/>能调用哪些工具"]
    Policy --> Sandbox["Sandbox / Elevated<br/>在哪里执行"]
    Sandbox --> Host["Gateway host<br/>真实资源"]

    style Access fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
    style Route fill:#dbeafe,stroke:#3b82f6,stroke-width:2px
    style Context fill:#dbeafe,stroke:#3b82f6,stroke-width:2px
    style Policy fill:#dcfce7,stroke:#22c55e,stroke-width:2px
    style Sandbox fill:#fee2e2,stroke:#ef4444,stroke-width:2px
    style Host fill:#f3f4f6,stroke:#6b7280,stroke-width:2px

1. 官方安全模型:先定 trust boundary

OpenClaw 官方安全文档明确把默认模型定义为个人助理部署:一个 Gateway 对应一个可信 operator boundary,可以有多个 Agent,但不把同一个 Gateway 当成多个敌对租户之间的强隔离边界。

这句话要先理解:一个 shared gateway 不适合承载互不信任的敌对用户。

如果你要让陌生人、客户、外部用户共享一个能跑工具的 Agent,不应该只靠 prompt 或 allowlist。更稳妥的拆法是:

  • Gateway 控制面:分 Gateway。
  • 凭据和 channel token:分 credentials。
  • OS 级资源:分 OS user、host 或 VPS。
  • 工具执行能力:每个 Agent 只拿自己需要的 sandbox 和 tool policy。

如果多个不可信用户能给同一个 tool-enabled Agent 发消息,官方建议把他们视为共享了这个 Agent 的 delegated tool authority。也就是说:他们不是彼此隔离的安全主体。

shared Gateway 可以是个人助理系统,不应该被误当成强多租户隔离平台。

2. Channel 只负责消息入口和回路

Channel 是消息入口抽象。Telegram、WhatsApp、Discord、Slack、Signal、iMessage、LINE、IRC、Google Chat 以及扩展渠道进来的消息,会被 Gateway 标准化,再进入 Agent。

但不要误解为“模型自己决定发回哪里”。官方 Channel Routing 文档说得很清楚:

回复回到原消息来源;模型不选择 channel;路由由 host configuration 决定。

几个关键词:

  • Channel:消息平台,例如 telegram、whatsapp、discord、slack;安全上看平台入口是否允许。
  • AccountId:同一 channel 下的账号实例;安全上看多账号默认账号是否明确。
  • AgentId:独立 workspace + session store;安全上看消息最终进哪个 Agent。
  • SessionKey:上下文桶;安全上看是否串上下文、是否影响工具运行姿态。

多账号场景要设置明确默认账号,例如 channels.telegram.defaultAccountaccounts.default。否则 fallback routing 可能拿到第一个 normalized account id,这在安全审计里很难解释。

3. 路由是确定性的,不是模型猜的

OpenClaw 选择 Agent 的顺序是确定规则:

优先级匹配规则用途
1Exact peer match精确发送者或会话绑定
2Parent peer matchthread inheritance
3Discord guild + roles matchDiscord 角色分流
4Discord guild matchDiscord 服务器分流
5Slack team matchSlack team 分流
6Account match同一平台多账号分流
7Channel match按平台默认分流
8Default agent兜底 Agent

Session key 形态也由来源决定:

  • Direct DM:agent:agentId:mainKey
  • Group:agent:agentId:channel:group:id
  • Room/channel:agent:agentId:channel:channel:id
  • Slack thread:base key 后追加 thread:threadId
  • Telegram topic:group key 内包含 topic:topicId

注意:DM 默认可能落入 main session,但外部 DM 的 sandbox 和 tool policy 会使用派生 runtime key,不会被当成本地 main-session run 处理。这个细节是为了避免“外部渠道消息看起来像本机主会话”的安全错觉。

路由确定性是安全资产。能解释一条消息为什么进某个 Agent,后续才谈得上审计和收紧。

4. DM access:pairing 是默认安全起点

所有当前支持 DM 的渠道都有 DM policy。它在消息被处理前先挡住入站 DM。

四种策略:

dmPolicy行为风险判断
pairing默认。未知发送者拿到短码,owner approve 前消息不会被处理私人 Agent 的默认安全起点
allowlist只允许 allowFrom 或 pairing allow-store 中的发送者适合固定联系人
open允许所有入站 DM,必须显式 allowFrom: ["*"]只适合非常受限的工具能力
disabled忽略所有入站 DM适合关闭外部私信入口

Pairing 的官方细节:

  • 配对码:8 位、大写、避开易混字符 0O1I
  • 过期时间:1 小时。
  • 同一 sender:约每小时只会创建一次新请求。
  • pending 数量:每个 channel 默认最多 3 个 pending requests。
  • approve 前:未知 sender 的消息不会进入 Agent。

审批命令:

openclaw pairing list telegram
openclaw pairing approve telegram PAIRCODE

DM 配对状态在 Gateway host 上,默认路径:

默认文件包括 ~/.openclaw/credentials/channel-pairing.json~/.openclaw/credentials/channel-allowFrom.json~/.openclaw/credentials/channel-accountId-allowFrom.json

这些文件是访问控制数据,按敏感文件处理。

5. DM isolation:不要把多人 DM 放进一个上下文

DM access 解决“谁能说话”。DM isolation 解决“谁和谁共享上下文”。

如果只有你一个人用私人 Agent,session.dmScope: "main" 可以保持连续性。

如果多个人能 DM:

{
  "session": {
    "dmScope": "per-channel-peer"
  }
}

官方的 shared inbox quick rule:

  • 多人可 DM:用 per-channel-peer
  • 多账号 channel:用 per-account-channel-peer
  • 固定联系人:保持 dmPolicy: "pairing" 或严格 allowlist。
  • shared inbox + 工具能力:不要和 broad tool access 放在一起。

这仍然不是敌对多租户隔离。它只是把 cooperative shared inbox 做得更稳。

dmPolicy 管“谁能进来”,dmScope 管“谁和谁共享上下文”。这两个必须一起看。

6. Group access:allowlist 先于 mention

群组比 DM 更危险,因为消息来源更多,历史上下文更杂。

官方 Groups 文档的默认行为:

  • groupPolicy 默认 allowlist:群组不是默认全开放入口。
  • 群组回复默认需要 mention:不被 @ 时通常不应主动回复。
  • Heartbeat 会跳过 group sessions:周期提醒不应自动打扰群组。

群组消息的判断顺序:

  1. 先看 groupPolicydisabledallowlist 还是 open,决定群组入口是否进入处理链路。
  2. 再看 Group allowlists 是否允许这个群、房间或 sender。
  3. 最后看 requireMention / activation 是否允许触发回复。

groupPolicy 和 mention gating 是两件事:

  • groupPolicy 决定这个群组或房间能不能进入处理链路。
  • requireMention 决定是否必须 @ 到 bot 才触发回复。

安全默认:

{
  "channels": {
    "whatsapp": {
      "groupPolicy": "allowlist",
      "groupAllowFrom": ["+15551234567"],
      "groups": {
        "*": { "requireMention": true }
      }
    }
  }
}

DM pairing approval 不等于 group authorization。批准某人私信,只是让他能 DM;不代表他能在群里触发命令。

7. Context visibility:触发权限不等于上下文过滤

官方安全文档把两件事分开:

  • Trigger authorization 问“谁能触发 Agent”,例如 sender、group、room 是否 allowlisted。
  • Context visibility 问“哪些补充上下文进入模型输入”,例如 quote、thread history、forward metadata。

补充上下文包括 reply body、quoted text、thread history、forwarded metadata。默认 contextVisibility: "all" 会尽量保持正常聊天体验,但这不代表所有 quoted/history 内容都经过了同等 allowlist 过滤。

可选模式:

contextVisibility行为适合场景
all默认,按收到的上下文保留私人或可信群组
allowlist只保留 active allowlist 允许 sender 的补充上下文更强上下文过滤
allowlist_quote类似 allowlist,但保留显式 quote/reply 例外需要回复引用上下文,但仍要收紧

这对群聊尤其重要:一个非 allowlisted sender 不能触发 Agent,不代表他的历史消息永远不会以 thread/quote context 形式被模型看到。需要强边界时,把 contextVisibility 配到 channel 或具体 room/conversation。

触发权限不是上下文过滤。能不能让 Agent 开口,和哪些历史内容进入模型,是两条不同的安全链路。

8. 工具安全分三层

OpenClaw 有三个相关但不同的控制:

  • Sandbox:决定工具在哪里运行,比如 host、Docker、SSH、OpenShell;这是运行环境边界。
  • Tool policy:决定哪些工具存在、可调用;这是能力边界。
  • Elevated:决定 sandboxed exec 是否有出沙箱逃生口;只影响 exec

Sandbox mode:

Sandbox mode行为适合场景
off全部工具在 host 上运行只适合可信个人入口
non-main只有 non-main sessions sandboxed群组、channel、外部入口常见选择
all所有 session 都 sandboxed更严格的默认隔离

Tool policy 规则:

  • deny 永远优先:明确禁止不能被后续 allow 覆盖。
  • allow 非空时,没列入的工具都被 blocked:allowlist 是收紧模式。
  • /exec 不能覆盖被 tool policy deny 的 exec:用户命令不能越过硬 policy。
  • Provider-specific policy 可覆盖:可以按 provider 或 provider/model 定制。
  • Sandbox tool policy 只在 sandboxed 时生效:要先确认 session 是否真的 sandboxed。

Elevated 规则:

  • on / ask:出沙箱但保留 approvals,需要人工确认。
  • full:出沙箱并跳过 exec approvals,风险最高。
  • 未启用或 sender 未 allowlisted:不允许 elevated,默认更稳。

Elevated 不授予额外工具,不覆盖 tool allow/deny;它只在 agent sandboxed 且影响 exec 时改变运行位置。

调试实际生效规则:

openclaw sandbox explain
openclaw sandbox explain --session agent:main:main
openclaw sandbox explain --agent work
openclaw sandbox explain --json

9. Sandbox bind mounts 是真实穿透口

Docker sandbox 不是魔法墙。你挂载什么,容器里就能看到什么。

官方安全要点:

  • docker.binds 会穿透 sandbox filesystem,挂进去的路径,容器里就能看见。
  • 不写 mode 时默认 read-write,敏感路径优先 ro
  • workspaceAccess 独立于 bind mode,workspace 权限和额外挂载权限分开判断。
  • 绑定 /var/run/docker.sock 等于把 host 控制权交给 sandbox。
  • Symlink-parent escapes 已有校验,但仍不要把敏感目录放进 allowed roots。

群组和公共 Agent 的更稳写法:

{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "non-main",
        "scope": "session",
        "workspaceAccess": "none",
        "docker": {
          "binds": ["/home/user/PublicDocs:/data:ro"]
        }
      }
    }
  },
  "tools": {
    "sandbox": {
      "tools": {
        "allow": ["group:messaging", "group:sessions"],
        "deny": ["group:runtime", "group:fs", "group:ui", "nodes", "cron", "gateway"]
      }
    }
  }
}

这不是为了“让模型更乖”,而是让模型就算被诱导,也没有能力碰 host 文件和 shell。

Sandbox 不是口头承诺。真正要检查的是 bind mounts、workspaceAccess、tool allow/deny 和 elevated gates 的组合。

10. Prompt injection 没有被解决

Prompt injection 是攻击者把恶意指令塞进消息、网页、邮件、附件、日志或文件,让模型把外部内容误当成操作指令。

官方安全文档的立场很现实:

强 system prompt 只是 soft guidance;硬边界来自 tool policy、exec approvals、sandboxing、channel allowlists。

应该视为不可信的内容:

  • “读这个文件或 URL,然后照里面说的做。”风险是外部内容伪装成操作指令。
  • “忽略 system prompt 或安全规则。”风险是试图覆盖上层约束。
  • “输出 hidden instructions 或 tool outputs。”风险是诱导泄漏内部上下文。
  • “粘贴 ~/.openclaw 或日志的完整内容。”风险是诱导泄漏配置和 transcript。
  • 网页、邮件、附件、转发消息、群聊历史、粘贴的日志和代码,都可能把外部输入混入模型上下文。

实际防御:

  • 入口:入站 DM 用 pairing 或 allowlist。
  • 群组:用 mention gating,不做 public room always-on bot。
  • Agent profile:触碰不可信内容的 Agent 用 read-only 或 tool-disabled profile。
  • 高风险工具:execbrowserweb_fetchweb_search 只给可信 Agent。
  • 解释器:需要 allowlist 时,启用 tools.exec.strictInlineEval
  • 秘密:不放进 prompt,放在 Gateway host 的 env/config 中。
  • 模型:Tool-enabled Agent 选更新、更强的 instruction-hardened model。

不要承诺“防住所有 prompt injection”。正确目标是:注入即使成功,也不能变成文件、shell、网络、浏览器、凭据泄露的真实动作。

11. Browser 和插件也属于攻击面

Browser control 风险不低。Host browser profile 可能有登录态、cookie、后台账号。官方建议:

  • 给 Agent 用专用 profile,避免复用个人登录态。
  • 不要指向日常浏览器 profile,cookie、后台账号、历史记录都可能暴露。
  • Sandboxed agents 不默认启用 host browser control,否则会绕回 host 侧高权限面。
  • 严格环境收紧 Browser SSRF policy,private/internal destinations 默认禁掉,再用 allowlist 开例外。

Plugin 也不是普通配置。Plugin 在 Gateway 进程内运行,应该当作可信代码:

  • 只装可信来源,因为 Plugin 在 Gateway 进程内运行。
  • plugins.allow 做显式 allowlist,避免随意加载。
  • 安装和更新前看清配置,配置本身可能扩大权限。
  • 更新 plugin 后重启 Gateway,确保加载状态一致。
  • 谨慎使用 dangerously-force-unsafe-install,只作为 false positive 的 break-glass。

12. Gateway 暴露面:默认 loopback,不要裸奔

Gateway 默认端口是 18789,WebSocket 和 HTTP 共用这个端口。HTTP surface 包括 Control UI、canvas host 等。

安全规则:

  • gateway.bind: "loopback" 是默认值,只允许本地客户端连接。
  • "lan""tailnet""custom" 都会扩大攻击面。
  • 非 loopback bind 必须配 Gateway auth、真实 firewall、可信反代或 Tailscale 方案。
  • Tailscale Serve 优先于 LAN bind。
  • 必须 LAN bind 时,firewall 只允许极小 source IP 集合。
  • unauthenticated 0.0.0.0 不应出现。

最小安全基线:

{
  "gateway": {
    "mode": "local",
    "bind": "loopback",
    "auth": {
      "mode": "token",
      "token": "replace-with-long-random-token"
    }
  },
  "session": {
    "dmScope": "per-channel-peer"
  },
  "tools": {
    "profile": "messaging",
    "deny": ["group:automation", "group:runtime", "group:fs", "sessions_spawn", "sessions_send"],
    "fs": { "workspaceOnly": true },
    "exec": { "security": "deny", "ask": "always" },
    "elevated": { "enabled": false }
  },
  "channels": {
    "whatsapp": {
      "dmPolicy": "pairing",
      "groups": {
        "*": { "requireMention": true }
      }
    }
  }
}

13. 日志、transcripts、配置都是敏感数据

即使访问控制正确,日志和 transcript 也会泄露信息。

官方提醒的敏感位置:

  • ~/.openclaw/openclaw.json:Gateway、channel、tool、auth 配置。
  • ~/.openclaw/agents/agentId/sessions/sessions.json:session 路由和状态。
  • ~/.openclaw/agents/agentId/sessions/*.jsonl:transcript、工具调用和结果。
  • ~/.openclaw/sandboxes/:sandbox 运行产物。
  • /tmp/openclaw/openclaw-YYYY-MM-DD.log:日志和排障信息。

建议:

  • ~/.openclaw 目录权限保持 700,限制本机其他用户读取。
  • openclaw.json 保持 600,避免配置泄露。
  • 保持 logging.redactSensitive: "tools",对工具输出脱敏。
  • 增加 logging.redactPatterns,遮盖内部域名、token、hostnames。
  • 对外排障优先给 openclaw status --all,避免直接贴 raw logs。
  • 清理旧 transcripts 和 logs,降低历史泄露面。
  • 共享 host 用专用 OS user 跑 Gateway,限制横向读取。

14. 安全审计和应急

改配置、开新 channel、暴露网络面之后,跑:

openclaw security audit
openclaw security audit --deep
openclaw security audit --json

--fix 只做窄修复:收紧常见 open group policies、恢复敏感日志脱敏、修 state/config/include-file 权限等。不要把它当成全自动安全加固。

如果怀疑暴露或泄露:

  1. Contain:停 Gateway,临时改回 gateway.bind: "loopback",DM/group 改 disabled 或 require mention,并移除 "*" allow-all。
  2. Rotate:换 gateway.auth.tokenOPENCLAW_GATEWAY_PASSWORD,换 remote client token/password,换 channel tokens、model keys、auth-profiles、encrypted secrets。
  3. Audit:查 Gateway logs、相关 session transcripts 和近期 config diff,再重跑 openclaw security audit --deep

15. 给 Agent 的实践任务

把这组要求发给 OpenClaw Agent,让它审计自己的入口安全:

  1. 只读审计当前 OpenClaw Gateway 的 Channel 与安全配置,不要直接修改文件。
  2. 运行 openclaw security audit --deep,并按 critical / warn / info 分类总结。
  3. 检查 gateway.bindgateway.authgateway.port,说明是否存在非 loopback 暴露或弱认证。
  4. 检查所有 channels 的 dmPolicyallowFromgroupPolicygroupsgroupAllowFromrequireMention
  5. 检查 session.dmScope;如果多用户 DM 仍然使用 main,指出风险。
  6. 检查 contextVisibility 是否适合群聊或公开频道。
  7. 运行 openclaw sandbox explain --json,说明 sandbox mode、workspaceAccess、tool allow/deny、elevated gates。
  8. 检查是否给公共或群组 Agent 开了 execbrowserweb_fetchweb_searchgatewaycronsessions_sendsessions_spawn
  9. 检查日志、transcripts、credentials、pairing store 的权限和敏感信息暴露风险。
  10. 输出最小修复建议,按“必须修 / 建议修 / 可观察”分组。

16. 本章自检

读完这一章,你应该能回答:

  1. OpenClaw 为什么不把一个 shared Gateway 当成敌对多租户隔离边界?
  2. Channel routing 为什么是确定性的?
  3. dmPolicy: "pairing"session.dmScope 分别解决什么问题?
  4. 为什么 DM pairing approval 不等于 group authorization?
  5. groupPolicy、group allowlist、mention gating 的判断顺序是什么?
  6. Trigger authorization 和 context visibility 的区别是什么?
  7. Sandbox、tool policy、elevated 分别控制什么?
  8. 为什么 denyallow 优先?
  9. Prompt injection 为什么不能靠 system prompt 彻底解决?
  10. 为什么 Gateway 默认应该保持 loopback?

过关标准:能把一次外部消息拆成“入口授权 → 路由 → 上下文可见性 → 工具策略 → 运行环境 → 日志与配置保护”六层检查。

17. 接下来去哪

18. 官方资料

本页目录