乐于分享
好东西不私藏

OpenClaw安全加固系列(一):信任模型与安全边界

OpenClaw安全加固系列(一):信任模型与安全边界

有没有想过一个问题:

你给 Agent 配了工具权限,说”你可以执行命令”。但是——”你”是谁?谁给你这个权限?Agent 怎么知道发消息的这个人真的是你,而不是哪个路人?

这就是安全领域的第一个问题:信任模型

不把这个讲清楚,后面聊什么沙箱、什么权限白名单,都是空中楼阁。


先说说 OpenClaw 的安全设计前提。官方文档里有这么一句话:

OpenClaw 假设每位 Agent 服务于一个受信任的主体。它不是为”多个互不信任的人共用同一个 Agent”设计的。

翻译成人话:你的 Agent 默认只信任你一个人。 如果有人要共用,你得自己去搭隔离。

这不是偷懒,是几乎所有 AI Agent 产品共同的底层假设。就像你手机——设计上就是给你一个人用的。你借给别人用一下没问题,但手机本身的设计前提是”一个主人”。

如果有人拿到你的手机就能解锁、能发消息,这不是手机的安全漏洞,是你把手机给了别人。OpenClaw 同理:谁有你的配置文件和 Bot Token,谁就是 Agent 的主人。

这个前提搞清楚了,才能往下聊具体的控制手段。


第一道门:谁可以给你的机器人发消息?

OpenClaw 接入 Telegram 后,理论上任何知道你机器人用户名的人都可以给它发消息。Agent 有工具权限,陌生人能调用,等于陌生人也能操控你的工具。

所以第一件事就是装个”门禁”。

配置里两个字段配合使用:

"channels": {  "telegram": {    "dmPolicy""allowlist",    "allowFrom": ["${TG_ALLOWFROM_ID}"]  }}

  • dmPolicy: "allowlist":打开白名单模式——这是开关
  • allowFrom:谁是白名单里的人——这是名单

两个缺一不可。光开开关没写名单,门锁了但钥匙没人有,谁都进不来;光写名单没开开关,门没锁,名单写谁都没用。

对应的配置文件字段:channels.telegram.dmPolicy + channels.telegram.allowFrom,没有第二个未经授权的人能给我的机器人发消息。


第二道门:谁的 Telegram 消息交给谁处理?

装好门禁了,接下来是”路由”。

你可能有多个场景:自己日常用、测试用、家人用。你不想让他们的消息都走到同一个 Agent 里。所以 OpenClaw 有一个叫 bindings 的机制——决定”哪个 Telegram 账号的消息,由哪个 Agent 来回复”。

但这里有个容易被误解的地方:bindings 不是安全控制,是消息路由。

安全把关是 dmPolicy + allowFrom 那一层做完了的——只有白名单里的人的消息才能进来。bindings 是在”人已经进来了、验证通过了”之后,决定”该让谁处理这条消息”。

那 bindings 有没有安全价值?有。你可以通过 bindings 把用户路由到沙箱里的 Agent。即使攻击者拿到了 Bot Token,也只能在沙箱里活动,碰不到宿主机。

对应的配置文件字段:

"bindings": [  { "agentId": "A", "match": { "channel": "telegram", "accountId": "A" } },  { "agentId": "B", "match": { "channel": "telegram", "accountId": "B" } }]
agentId 决定消息交给谁,match.accountId 匹配具体的 Telegram 机器人账号。

我们当前的路由:

我 → A 机器人 → A Agent(Docker 沙箱)
我 → B 机器人 → B Agent(SSH 沙箱)

两个入口,两个独立的 Agent,各有一个沙箱兜底。


第三件事:不要把个人和公司的 Agent 混在一起

这是很多人(包括曾经的我)容易忽略的问题。

如果你在一个 Gateway 实例上同时跑了两个 Agent:一个管你的个人聊天,另一个连你公司的 Jira——表面上是两个独立的 Agent,但它们底层共享同一个进程、同一份配置、同一组环境变量。

风险不在”Agent 之间会串话”——会话层有隔离,A 的聊天内容不会被 B 看到。风险在共享的基础设施层

个人 Agent 能读到的环境变量,公司 Agent 也能读到。如果有人攻破了公司 Agent(比如公司群里有人诱导它执行 echo $DEEPSEEK_API_KEY),你个人的 API Key 就被泄漏了。

这不是危言耸听。我们自己测试过——在同一个 Gateway 下,A Agent 的环境变量,B Agent 确实可以直接读到。

正确的做法:

个人电脑上跑个人的 OpenClaw,公司的部署在独立服务器上。两套 Gateway,互相隔离。

对应的配置:这不是一个开关,而是架构决策——两台机器,两套 openclaw.json,两套环境变量,完全隔离开。

当然,如果你像我一样只是个人用,没有公司场景——那这节当你看到了一条知识就行,暂时不用担心。


安全边界:你的防线划在哪一层?

前面聊的都是”信任谁”,但安全还有一个同样重要的问题:边界在哪?

理解 OpenClaw 的安全边界,其实就是搞清楚每一层防线分别挡住了什么:

你(用户)  ↓ Gateway 边界:谁可以连接我的 OpenClaw 服务?  ↓ Telegram 边界:谁可以给我的机器人发消息?  ↓ 路由边界:消息进了系统,由哪个 Agent 处理?  ↓ 工具边界:Agent 能调用哪些工具?  ↓ 执行边界:工具在沙箱里跑还是在宿主机上跑?  ↓ 资源边界:沙箱能用多少 CPU、内存?
每一层都是一条边界线。如果攻击者突破了第一层,还有第二层等着他。

具体到你现在的环境,每条边界对应的配置字段:

第一道边界(网络层) — Gateway 绑了 loopback,只有你本机能连。Token 认证进一步确保本机其他进程也不能随便调用 API。

对应配置:gateway.bind: "loopback" + gateway.auth.mode: "token"


第二道边界(消息层) — Telegram 白名单只放行了你的 ID,其他人的消息到不了 Agent。

对应配置:channels.telegram.dmPolicy: "allowlist" + allowFrom: ["${TG_ALLOWFROM_ID}"]


第三道边界(路由层) — bindings 把你的消息路由到 Docker 沙箱里的 argus Agent,而不是裸奔的那个。

对应配置:bindings[].agentId: "argus" + match.accountId: "argus"


第四道边界(权限层) — tools.allow 只列了 read / write / exec 等必要工具,tools.deny 禁用了 process、gateway、sessions_spawn 等高风险操作。elevated.enabled: false 禁止 Agent 请求提权逃逸。

对应配置:tools.allow / tools.deny / elevated.enabled: false


第五道边界(执行层) — Docker 沙箱把 Agent 关在容器里,capDrop: ALL 砍掉所有内核能力,readOnlyRoot 禁止修改系统文件,tmpfs 让临时文件不留磁盘。三层锁叠在一起。

对应配置:sandbox.mode: "all" + docker.capDrop: ["ALL"] + docker.readOnlyRoot: true + docker.tmpfs


第六道边界(资源层) — 内存 4G、CPU 2 核、进程数 256 上限——攻破了沙箱也掀不起大浪。

对应配置:docker.memory: "4g" / docker.cpus: 2 / docker.pidsLimit: 256

安全不是一堵墙,是一层一层的洋葱皮。每一层都让攻击者多花一份力气。