乐于分享
好东西不私藏

OpenClaw 安全第六课:Token 认证的正确姿势

OpenClaw 安全第六课:Token 认证的正确姿势

阅读前记得关注+星标,及时获取更新推送

OpenClaw 安全加固系列 第6篇 前五篇我们把网络层封死了:端口改了、SSH 锁了、Gateway 绑到 loopback 或 tailnet。

但还有一个问题:如果有人通过合法渠道(SSH Tunnel、Tailnet)访问到了 Gateway,Token 是最后一道门。这道门够不够结实?

默认 Token 的三个问题,以及怎么解

OpenClaw 默认的 Token 配置非常简单,只做了最基础的"有没有 Token"校验,存在三个明显缺陷:

问题 1:无过期时间

Token 一旦生成,永久有效。如果 Token 泄露(被 prompt injection 读走、出现在日志里、被截包),攻击者可以永远使用它。

解法:OpenClaw 源码目前没有内置 TTL 机制。用 cron job 定期轮换来替代——每天自动生成新 Token 并重启 Gateway,泄露的 Token 最多用一天。后面有完整脚本。

问题 2:无 IP 绑定

同一个 Token 可以从任何 IP 使用。攻击者拿到 Token 后,理论上可以从世界任何地方访问你的 Gateway。

解法:这个问题不靠 Token 解决,靠网络层解决。前几篇配置的 loopback / tailnet 模式,Gateway 本身就不对公网暴露,外部根本连不进来。Token 只是最后一道门,门前的路已经封死了。如果你已经做了第三篇或第四篇的配置,这个问题已经解决了。

问题 3:无设备指纹校验

无法区分是你的设备在用,还是别人拿着你的 Token 在用。

解法:OpenClaw 没有内置设备指纹支持。实际防御靠两件事的组合:Token 强度(32 字节随机,暴力破解不现实)+ 网络隔离(只有 Tailnet 内的设备能访问)。两者结合后,设备指纹校验的必要性大幅降低——攻击者既拿不到 Token,也进不了网络。

源码里的 Token 验证逻辑

OpenClaw Gateway 的 Token 验证在 src/gateway/middleware/auth.ts 里:

export function authMiddleware(config: GatewayConfig) {  return (req: Request, res: Response, next: NextFunction) => {    const token = req.headers['authorization']?.replace('Bearer ', '')                  || req.query.token as string;    // 默认配置:只检查 token 是否匹配,没有过期、没有 IP 校验    if (config.auth?.mode === 'token') {      if (token !== config.auth.token) {        return res.status(401).json({ error: 'Unauthorized' });      }    }    next();  };}

就这么简单。字符串比对,匹配就放行,不匹配就 401。没有过期时间,没有 IP 检查,没有任何额外校验。

生成一个强 Token

先把默认的弱 Token 换掉。

# 生成 32 字节的强随机 Tokenopenssl rand -hex 32# 输出示例:a3f8c2e1d4b7a9f0e2c5d8b1a4f7c0e3d6b9a2f5c8e1d4b7a0f3c6e9d2b5a8f1# 或者用 Pythonpython3 -c "import secrets; print(secrets.token_hex(32))"

写入配置文件:

{  "gateway": {    "auth": {      "mode": "token",      "token": "a3f8c2e1d4b7a9f0e2c5d8b1a4f7c0e3d6b9a2f5c8e1d4b7a0f3c6e9d2b5a8f1"    }  }}

不要用这个示例 Token,自己生成一个。

加固配置

OpenClaw 目前支持的 Token 配置比较简单,核心就是设置一个强随机 Token:

{  "gateway": {    "auth": {      "mode": "token",      "token": "你生成的强随机Token"    }  }}

token_ttlrequire_device_fingerprint 等高级字段在当前版本源码中未经证实支持,不建议写进配置文件,避免被忽略或产生意外行为。

Token 定期轮换用 cron job 实现:

# 写一个轮换脚本 /usr/local/bin/rotate-openclaw-token.sh#!/bin/bashNEW_TOKEN=$(openssl rand -hex 32)jq --arg t "$NEW_TOKEN" '.gateway.auth.token = $t' \  ~/.openclaw/openclaw.json > /tmp/oc.tmp \  && mv /tmp/oc.tmp ~/.openclaw/openclaw.jsondocker restart openclawecho "[$(date)] Token rotated" >> /var/log/openclaw-token.log# 加执行权限chmod +x /usr/local/bin/rotate-openclaw-token.sh# 每天凌晨 3 点自动轮换echo "0 3 * * * /usr/local/bin/rotate-openclaw-token.sh" | crontab -

Token 泄露了怎么办

立即吊销,重新生成:

# 生成新 TokenNEW_TOKEN=$(openssl rand -hex 32)# 更新配置文件# 用 jq 修改(如果安装了 jq)jq --arg t "$NEW_TOKEN" '.gateway.auth.token = $t' \  ~/.openclaw/openclaw.json > /tmp/openclaw.json.tmp \  && mv /tmp/openclaw.json.tmp ~/.openclaw/openclaw.json# 重启 Gateway 使新 Token 生效docker restart openclawecho "新 Token: $NEW_TOKEN"

重启后旧 Token 立即失效。

Token 不要放在配置文件里

配置文件可能被 prompt injection 读走(第五篇讲过)。更安全的做法是用环境变量:

docker run -d \  --name openclaw \  -e OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)" \  openclaw/openclaw

OpenClaw 会优先读取环境变量 OPENCLAW_GATEWAY_TOKEN,配置文件里的 token 字段留空或删掉。

这样即使攻击者读到了配置文件,也拿不到 Token。

检查 Token 是否在日志里泄露

Token 有时候会意外出现在日志里(比如作为 URL 参数传递):

# 检查 OpenClaw 日志里有没有 Tokendocker logs openclaw 2>&1 | grep -i "token\|authorization\|bearer"# 检查系统日志sudo grep -r "18789" /var/log/ | grep -i "token"

如果发现 Token 出现在日志里,立即轮换。

防护效果

场景
无 Token
弱 Token
强 Token + 定期轮换
未授权访问
✅ 可访问
❌ 被拦截
❌ 被拦截
Token 泄露后
-
✅ 永久可用
❌ 轮换后立即失效
暴力破解
-
⚠️ 短 Token 有风险
❌ 32字节熵太高
配置文件被读
-
✅ Token 暴露
❌ 环境变量不在文件里

下一篇

Token 保护了 Gateway 的访问入口。但如果攻击者通过 Skill 植入恶意代码,Token 也帮不了你。

下一篇:《OpenClaw 安全第七课:Skill 白名单 - 第三方代码的沙箱》