1. 项目概述:为你的AI助手戴上“安全手套”

最近在折腾本地AI助手,特别是像OpenClaw这种能直接调用系统Shell、读写文件的“智能副驾”,效率提升是肉眼可见的。但用着用着,心里总有点发毛:万一它被一个精心构造的恶意网页或邮件诱导,执行了 rm -rf / 怎么办?或者一个无限循环的请求直接烧光了我的API额度?这感觉就像给了AI一把万能钥匙,却不知道它下一秒会开哪扇门。

这就是我动手搞 OpenClawGuard 的初衷。它不是什么复杂的系统,本质上就是一个 智能代理中间件 。你可以把它理解成AI助手和外部世界之间的“安全审查员”和“流量调度员”。所有发给OpenClaw的请求,无论是代码补全、Shell命令还是文件操作,都会先经过OpenClawGuard的检查站。在这里,危险的命令会被直接拦截,敏感的文件访问会被重定向到沙箱,需要写权限的操作会弹出通知等你拍板,甚至还能给API Token消耗装上“保险丝”,防止意外超支。

如果你也在用Cursor、Claude Desktop或者任何基于OpenClaw的本地AI工具,并且希望在不牺牲便利性的前提下,给它们套上一层可靠的安全边界,那么接下来的内容就是为你准备的。我会从设计思路、核心模块的实战配置,到那些只有踩过坑才知道的调试技巧,毫无保留地拆解一遍。

2. 核心安全架构与设计哲学

2.1 为什么是“代理”模式?

在构思安全方案时,我首先排除了直接修改OpenClaw源码这条路。原因很简单:一是侵入性强,每次OpenClaw更新都可能带来兼容性灾难;二是通用性差,你的改动很难惠及其他用户。 代理模式 成了最优雅的选择。它像一道透明的墙,立在客户端(如你的IDE)和OpenClaw服务之间。对客户端来说,它访问的依然是“OpenClaw”(实际上是Guard的端口);对OpenClaw来说,它接收的请求都来自“一个可信的客户端”(即Guard)。这种旁路设计,实现了 即插即用 零侵入

注意 :代理模式的关键在于“透明转发”。Guard必须完整地处理HTTP协议,包括头部信息、流式响应(对于Completions API至关重要)、以及可能的WebSocket连接(如果OpenClaw支持)。这意味着你不能用一个简单的请求转发库了事,需要自己处理TCP流和HTTP协议解析。

2.2 四重防护体系详解

OpenClawGuard的安全不是单点防御,而是一个分层递进的体系,我称之为“四重防护”。

第一重:命令过滤(静态规则) 这是最基础的防线。通过正则表达式匹配Shell命令中的危险模式,比如 rm -rf mkfs dd of= chmod 777 等。但光有模式匹配不够,一个 rm -f ./test 看起来无害,但如果当前目录是 / 呢?所以必须结合 路径敏感性检查 。Guard会解析命令中的路径参数,并与一个预定义的敏感路径列表(如 /etc , /boot , ~/.ssh , C:\Windows\System32 )进行比对。任何试图操作这些路径的命令,无论看起来多“温和”,都会被果断拦截。

第二重:人工审批(动态干预) 对于所有 写操作 (包括文件写入、修改、删除,以及可能改变系统状态的Shell命令如 apt install ),Guard不会立即放行。它会暂停这个请求,生成一个唯一的审批ID,然后通过你配置的通道(Telegram或企业微信)向你发送通知。只有当你点击“批准”后,这个操作才会被继续执行。这实现了 “Human-in-the-loop” ,把最高权限牢牢握在用户手里。这里的设计难点在于请求的暂停与恢复,需要妥善管理请求上下文和状态。

第三重:文件系统沙箱(访问重定向) AI助手经常需要读写文件来理解上下文。但让它自由访问整个硬盘风险太高。沙箱机制通过路径重写来实现。例如,你可以将沙箱根目录设置为 /workspace 。当AI请求读取 /home/user/project/src/main.py 时,Guard会将其重写为 /workspace/project/src/main.py 。所有文件操作都被限制在这个沙箱目录内。这需要Guard在转发请求前,对请求体(通常是JSON)中的文件路径进行实时查找与替换。

第四重:令牌熔断器(资源管控) 这是为了防止“提示词攻击”或bug导致的失控循环。Guard会统计经过它的所有请求所消耗的AI令牌数(Token)。你可以设置一个时间窗口(如24小时)内的上限(如10万个Token)。一旦累计消耗超过这个阈值,熔断器就会“跳闸”,后续所有请求都会被立即拒绝,并返回429(Too Many Requests)状态码,直到下一个时间窗口开始。这能有效防止因为一个无限循环的提示词而导致的巨额API账单。

3. 从零开始部署与配置实战

3.1 基础环境搭建

假设你已经有一个运行在 http://localhost:8080 的OpenClaw服务。我们的目标是在它前面架设Guard。

首先获取代码并安装依赖:

git clone https://github.com/taosin/openclaw-guard.git
cd openclaw-guard
pip install -r requirements.txt

核心依赖通常是 Flask (用于提供审批API)、 requests (用于转发HTTP请求)、以及 python-telegram-bot requests (用于发送通知)。确保你的Python版本在3.9以上。

最简启动方式如下:

python clawguard.py --target-port 8080

默认情况下,Guard会监听在 8081 端口。现在,你需要将你的客户端(例如Cursor的设置中的AI服务端点)从 http://localhost:8080 改为 http://localhost:8081 。至此,所有流量就开始流经你的安全网关了。

3.2 关键配置项深度解析

通过环境变量进行配置是最灵活的方式。以下是一些核心变量的详细说明,远超README中的简单列表:

1. 网络与目标服务配置

  • CLAWGUARD_PORT=8081 : Guard自身服务的端口。如果8081被占用,可以改为其他端口。
  • CLAWGUARD_TARGET_HOST=localhost : OpenClaw服务的主机名。在Docker容器内访问宿主机服务时,需改为 host.docker.internal
  • CLAWGUARD_TARGET_PORT=8080 : OpenClaw服务的端口。
  • CLAWGUARD_PUBLIC_URL=https://your-public-domain.com : 这是审批功能能用的关键! Guard需要生成供你点击的批准/拒绝链接。如果你只在本地使用,可以设为 http://localhost:8081 。如果你希望通过公网审批,则需要一个能被手机访问的公网地址,并配合内网穿透工具(如ngrok、frp)使用。例如,用ngrok: ngrok http 8081 ,然后将生成的 https://xxx.ngrok.io 设置为这个变量。

2. 安全策略配置

  • CLAWGUARD_SANDBOX=/workspace : 沙箱目录的绝对路径。确保运行Guard的用户对此目录有读写权限。所有AI发起的文件路径,都会被尝试重定向到这个目录下。例如,访问 /etc/passwd 会被重写为 /workspace/etc/passwd (通常不存在,因此会返回错误),从而保护真实系统文件。
  • CLAWGUARD_TOKEN_LIMIT=100000 : 令牌熔断器的上限。这个值需要根据你使用的AI模型和你的预算来设定。例如,GPT-4的输入输出都较贵,可以设低一些;如果是本地模型,可以设高或关闭。
  • CLAWGUARD_TOKEN_WINDOW_SEC=86400 : 统计时间窗口,单位秒。86400秒即24小时,实现了“每日限额”。如果你想做“每分钟限额”,可以设置为60。

3. 审批通道配置(二选一或同时使用)

  • Telegram Bot :
    • CLAWGUARD_TELEGRAM_BOT_TOKEN : 通过 @BotFather 创建机器人后获得的令牌。
    • CLAWGUARD_TELEGRAM_CHAT_ID : 你的Telegram用户或群组的Chat ID。可以通过给 @userinfobot 发送消息来获取。
    • 实操心得 :Telegram推送延迟低、交互方便,是首选。确保你的Bot已经 /start 过。
  • 企业微信(WeChat Work)机器人 :
    • CLAWGUARD_WECHAT_WEBHOOK_URL : 在企业微信群里添加“群机器人”后获得的Webhook地址。
    • 注意事项 :企业微信机器人消息格式是特定的JSON。Guard已经封装好了,你只需要填入正确的Webhook URL即可。适合国内环境使用。

3.3 使用Docker进行一体化部署

为了环境隔离和部署简便,强烈推荐使用Docker Compose。

# 1. 复制并编辑配置文件
cp docker-compose.example.yml docker-compose.yml
vim docker-compose.yml # 或使用任何文本编辑器

编辑 docker-compose.yml ,重点修改 environment 部分。一个典型的配置示例如下:

version: '3.8'
services:
  openclaw-guard:
    build: .
    ports:
      - "8081:8081" # 将宿主机的8081映射到容器的8081
    environment:
      - CLAWGUARD_PORT=8081
      - CLAWGUARD_TARGET_HOST=host.docker.internal # 从容器内访问宿主机上的OpenClaw
      - CLAWGUARD_TARGET_PORT=8080
      - CLAWGUARD_PUBLIC_URL=http://localhost:8081 # 本地使用
      - CLAWGUARD_SANDBOX=/workspace
      - CLAWGUARD_TELEGRAM_BOT_TOKEN=YOUR_BOT_TOKEN
      - CLAWGUARD_TELEGRAM_CHAT_ID=YOUR_CHAT_ID
    volumes:
      - ./workspace:/workspace # 将宿主机目录挂载为沙箱,这样文件能持久化
      - ./config:/app/config # 可选,挂载自定义配置文件
    restart: unless-stopped

关键点解析

  • CLAWGUARD_TARGET_HOST=host.docker.internal : 这是Docker提供的一个特殊域名,指向宿主机。前提是宿主机上的OpenClaw监听在 0.0.0.0 localhost 上,且防火墙允许容器访问。
  • volumes 中的 ./workspace:/workspace : 这是 沙箱持久化 的关键。将宿主机的一个目录(如 ./workspace )挂载到容器内的沙箱路径。这样,AI在容器内创建的文件,会实际保存在宿主机上,即使容器重启也不会丢失。
  • 如果OpenClaw也运行在Docker中,可以将它们放在同一个 docker-compose.yml 里,通过服务名(如 openclaw )进行通信,网络更稳定。

编辑完成后,一键启动:

docker-compose up -d

使用 docker-compose logs -f 可以查看实时日志,排查问题。

4. 核心功能模块的实战与调试

4.1 命令过滤模块:编写你自己的安全规则

Guard内置了一套基础的危险命令和敏感路径规则,但你可能需要根据自身工作环境进行定制。规则配置文件通常位于 core/security_rules.py 或类似位置。

自定义危险命令模式 : 危险命令通过正则表达式列表定义。例如,想增加对 systemctl 命令的谨慎对待(防止关机或禁用关键服务):

DANGEROUS_PATTERNS = [
    r'\brm\s+(-rf|-r\s+-f|-[rf]{2,})', # 原有的rm -rf
    r'\bmkfs\b', # 原有的格式化命令
    r'\bdd\s+.*(of=|/dev/)', # 原有的dd命令
    # 新增:谨慎对待systemctl stop/disable/restart 后面跟关键服务
    r'\bsystemctl\s+(stop|disable|restart)\s+(ssh|docker|nginx|mysql|postgresql)\b',
]
  • 原理 :正则 \bsystemctl\s+(stop|disable|restart)\s+(ssh|docker|...)\b 会匹配“systemctl”后跟空格,然后是“stop”、“disable”或“restart”之一,再跟空格,最后是列举的关键服务名之一。 \b 表示单词边界,防止匹配到像“mysqldump”这样的词。

自定义敏感路径 : 敏感路径列表用于检查命令参数中的路径。添加你不想被触碰的目录:

SENSITIVE_PATHS = [
    '/etc', '/boot', '/root', '/var/lib', '/usr/lib',
    '~/.ssh', '~/.aws', '~/.kube',
    'C:\\Windows\\System32', 'C:\\Program Files',
    # 新增:你的项目机密配置目录
    '/home/user/project/config/secrets',
    '/var/www/html/.env',
]

修改后,需要重启Guard服务使新规则生效。

4.2 人工审批流程:从触发到完成的内部流转

理解审批流程对 troubleshooting 至关重要。假设AI试图执行 echo "test" > /workspace/new_file.txt

  1. 请求拦截 :Guard的代理层识别出这是一个文件写操作(通过分析请求体或命令内容)。它不会转发给OpenClaw,而是暂停请求,在内存或数据库中创建一个 ApprovalRequest 对象,包含操作详情、唯一ID( approval_id )、时间戳和状态( pending )。

  2. 通知发送 :Guard调用配置的通知发送器(Telegram/WeChat),发送一条消息,例如:“🛡️ OpenClawGuard 需要您的批准。操作:写入文件 /workspace/new_file.txt 。内容: test 。 [批准] [拒绝]”。这里的链接形如 {PUBLIC_URL}/clawguard/approve?id={approval_id}

  3. 用户决策 :你在手机上点击“批准”。这会向Guard的审批API端点 ( /clawguard/approve ) 发送一个HTTP GET请求。

  4. 请求恢复 :Guard的API端点接收到请求,根据 approval_id 找到被暂停的原始请求上下文,将其状态改为 approved ,然后 原封不动地 将这个被暂停的请求转发给后端的OpenClaw服务执行。

  5. 结果返回 :OpenClaw执行的结果(成功或失败)再通过Guard返回给最初的客户端(如Cursor)。对于客户端而言,只是这次请求的响应时间变长了(因为包含了人工审批的等待时间)。

重要提示 :审批状态需要持久化存储(如SQLite或Redis),否则Guard进程重启会导致所有待审批请求丢失。检查你的Guard是否配置了正确的存储后端。

4.3 文件沙箱的实现与路径重写逻辑

路径重写是沙箱安全的核心,其逻辑比想象中要复杂,因为AI给出的路径可能是绝对路径、相对路径、包含 .. 父目录引用,甚至是带环境变量的路径。

Guard内部的重写函数大致会做以下几步:

  1. 规范化路径 :使用 os.path.normpath 清理路径中的 ./ ../ 。例如, /home/user/../project/.//src 会被规范为 /home/project/src
  2. 解析相对路径 :如果路径是相对的(如 ./config.yaml ),需要结合一个“当前工作目录”的上下文(这通常需要从AI的请求或会话中推断或模拟)来转换为绝对路径。
  3. 检查是否逃逸 :计算规范化后的绝对路径。检查这个路径是否在预设的 允许访问列表 (如果配置了)之外,并且是否试图访问 SENSITIVE_PATHS 中的目录。如果是,则触发拦截或重写。
  4. 执行重写 :如果路径不在敏感列表,但为了强制沙箱化,Guard会将其根目录替换为 CLAWGUARD_SANDBOX 。一个简单的实现是: new_path = os.path.join(SANDBOX_ROOT, os.path.relpath(abs_path, '/')) 。但这假设所有路径都从根 / 开始重写。更安全的策略是定义一个“重写基准目录”,比如只重写用户家目录( /home/user )下的路径到沙箱。

调试技巧 :你可以在Guard的日志中增加调试信息,打印出“原始路径”和“重写后路径”,来验证沙箱逻辑是否按预期工作。有时AI会使用 file:// 协议或特殊的URI格式,需要额外解析。

4.4 令牌熔断器的算法与统计

熔断器不仅仅是简单的计数器。它需要在一个滑动时间窗口内统计令牌消耗。一个简单而有效的实现是使用一个队列(Queue)或排序集合(Sorted Set)。

算法思路

  1. 每个请求经过时,Guard会从OpenClaw的响应头或响应体中解析出本次消耗的令牌数( tokens_used )。这要求OpenClaw的API返回此信息(通常标准兼容的API如OpenAI格式都会返回 usage 字段)。
  2. 将当前时间戳( timestamp )和 tokens_used 作为一个元组 (timestamp, tokens_used) 存入一个列表或Redis的Sorted Set中(以timestamp为score)。
  3. 当新的请求到来,需要判断是否熔断时: a. 清理队列:移除所有时间戳早于 当前时间 - TOKEN_WINDOW_SEC 的记录。 b. 计算总和:将队列中所有记录的 tokens_used 相加,得到窗口内的总消耗 total_tokens 。 c. 判断:如果 total_tokens >= TOKEN_LIMIT ,则触发熔断,返回429错误;否则,允许请求通过。
  4. 为了性能,这个清理和计算过程不需要每次请求都全量进行,可以定期(如每10秒)在后台线程中执行一次,并将当前的总消耗缓存起来。

配置建议 TOKEN_LIMIT 的设置需要参考你的AI服务商定价。例如,对于GPT-4,假设每1000个Token输入0.03美元,输出0.06美元。如果你想将单日成本控制在1美元以内,可以做一个粗略估算:1美元 / ((0.03+0.06)/2 per 1K tokens) ≈ 22,000 tokens。那么设置 TOKEN_LIMIT=20000 会是一个比较安全的起点。

5. 常见问题排查与性能优化实录

在实际部署和运行中,你肯定会遇到各种问题。下面是我踩过坑后总结的排查清单。

5.1 连接与网络问题

问题:客户端连接Guard失败(连接被拒绝)

  • 检查1:Guard进程是否在运行? ps aux | grep clawguard docker ps
  • 检查2:端口是否正确监听? netstat -tlnp | grep 8081 (Linux/Mac) 或 Get-NetTCPConnection -LocalPort 8081 (Windows PowerShell)。确保Guard绑定的是 0.0.0.0 而非 127.0.0.1 ,否则容器或外部网络无法访问。
  • 检查3:防火墙/安全组规则 :宿主机防火墙是否放行了8081端口?云服务器的安全组规则是否设置正确?

问题:Guard无法连接到后端的OpenClaw (Connection refused to target host:port)

  • 检查1:OpenClaw服务是否运行? 确认 CLAWGUARD_TARGET_PORT 指定的端口上有服务在监听。
  • 检查2:主机名解析(Docker环境下常见) :在Docker容器内, localhost 指向容器自己。要访问宿主机服务,必须使用 host.docker.internal (Mac/Windows Docker Desktop)或宿主机真实IP(Linux)。在Linux Docker原生环境中,可能需要使用 --add-host=host.docker.internal:host-gateway 启动参数或直接使用宿主机IP 172.17.0.1

5.2 审批流程故障

问题:收不到Telegram/企业微信审批通知

  • 检查1:环境变量是否正确? 确保 CLAWGUARD_TELEGRAM_BOT_TOKEN CLAWGUARD_TELEGRAM_CHAT_ID 已正确设置且无多余空格。对于企业微信,检查Webhook URL是否完整。
  • 检查2:Token和Chat ID是否有效? 可以手动用 curl 测试Telegram Bot API: curl -X POST https://api.telegram.org/bot<YOUR_BOT_TOKEN>/sendMessage -d chat_id=<YOUR_CHAT_ID> -d text="Test" 。如果失败,说明凭证有问题。
  • 检查3:网络连通性 :如果Guard运行在无法直接访问公网的服务器或容器内,需要配置代理。可以设置环境变量 HTTP_PROXY HTTPS_PROXY

问题:点击批准/拒绝链接没反应(404或500错误)

  • 检查1: CLAWGUARD_PUBLIC_URL 配置 :这是最常见的坑。你手机点击的链接是基于这个变量生成的。如果Guard运行在 localhost:8081 ,而你的手机和电脑不在同一个网络,手机自然无法访问 localhost 。你必须将这个地址设置为手机能访问到的地址。使用ngrok是最快的测试方法。
  • 检查2:审批ID过期或不存在 :Guard可能将审批请求存储在内存中。如果Guard进程在发送通知后、你点击链接前重启了,那么内存中的审批上下文就丢失了。解决方案是配置持久化存储,如Redis: CLAWGUARD_REDIS_URL=redis://localhost:6379/0

5.3 功能异常:命令未拦截、沙箱无效等

问题:危险的Shell命令没有被拦截

  • 检查1:请求是否经过了Guard? 确认你的客户端(Cursor等)配置的端点确实是Guard的地址(如 http://localhost:8081 ),而不是直连OpenClaw。
  • 检查2:命令识别逻辑 :Guard是通过分析HTTP请求体中的特定字段(可能是 command code 等,取决于OpenClaw的API格式)来提取命令的。查看Guard的源码,确认它解析的是正确的字段。可以在Guard代码中添加日志,打印出它提取到的原始命令字符串进行调试。
  • 检查3:规则匹配 :你尝试的命令可能不在默认的危险模式列表中。参考4.1节添加自定义规则。

问题:文件操作没有限制在沙箱内,还是访问到了系统文件

  • 检查1:路径重写逻辑 :在Guard日志中开启调试模式,查看“原始路径”和“重写后路径”是否按预期变化。可能AI使用了非标准路径格式。
  • 检查2:沙箱目录权限 :确保运行Guard的用户对 CLAWGUARD_SANDBOX 指向的目录有读写权限,否则重写后的路径访问会失败,但错误信息可能被AI或客户端吞掉。
  • 检查3:工作目录上下文 :AI发起的相对路径(如 file.txt )是基于哪个“当前目录”解析的?如果Guard错误地判断了当前目录,重写就会出错。这需要根据OpenClaw的API行为进行适配。

5.4 性能优化与高可用考量

Guard作为中间件,会引入额外的延迟(网络转发、安全检查、可能的审批等待)。以下是一些优化点:

  1. 启用流式响应(Streaming) :AI的Completions API通常支持流式传输( stream=true ),可以边生成边返回。Guard必须支持透传这种流式响应,而不是等待整个响应完成再转发。检查你的代理实现是否使用了支持流式转发的HTTP库(如 httpx 的异步客户端或 requests stream=True 模式)。
  2. 异步处理 :对于审批通知发送、令牌统计更新等非即时阻塞操作,可以使用异步任务队列(如Celery + Redis)或后台线程来处理,避免阻塞请求转发的主线程。
  3. 缓存静态规则 :将危险命令正则表达式、敏感路径列表等加载到内存中,避免每次请求都从文件或数据库读取。
  4. 熔断器状态持久化 :将令牌消耗统计存储在Redis等外部缓存中,这样即使Guard多实例部署,也能共享熔断状态,实现分布式限流。
  5. 监控与日志 :集成Prometheus Metrics,暴露如 requests_total commands_blocked approvals_pending tokens_used 等指标,方便用Grafana监控。结构化日志(JSON格式)便于用ELK或Loki收集分析。

最后,安全是一个持续的过程。OpenClawGuard提供了强大的基础框架,但最了解你工作环境和风险点的人是你自己。定期审查日志,根据实际遇到的情况调整安全规则,并保持对AI助手行为的适度关注,这才是人机协作的安全之道。这个项目本身也在持续迭代,如果你有好的想法或发现了问题,非常欢迎去GitHub仓库提交Issue或PR,共同打造更安全的本地AI应用环境。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐