protect-mcp 实战:为 Claude Code 接入 Cedar 策略门控与 Ed25519 签名审计链
2026/9/10 0:24:56 网站建设 项目流程

protect-mcp 实战:为 Claude Code 接入 Cedar 策略门控与 Ed25519 签名审计链

【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents

protect-mcp是 agents 仓库中一个面向 Claude Code 的插件(plugins/protect-mcp/README.md),它为每一个工具调用提供两层防护:调用前由 AWS 开源授权引擎 Cedar 执行策略评估(拒绝即拦截),调用后生成 Ed25519 签名的、哈希链式相连的不可篡改回执。本文以 skills/protect-mcp-setup/SKILL.md 为骨架,结合仓库内的真实钩子配置、测试夹具与配套 Agent,完整讲解从安装、策略编写、签名回收到离线验证的落地全流程。

Claude Code 工具调用存在三个审计缺口

Claude Code 暴露了BashEditWriteWebFetch等强大工具,默认状态下它们既没有策略约束,也没有审计痕迹。会话日志(session log)看似记录了操作,但本质上存在三个致命缺陷:

  • 可篡改(Mutable)——任何有权限的人都能编辑日志内容;
  • 未签名(Unsigned)——无法证明日志的完整性;
  • 依赖运营方(Operator-bound)——验证结果建立在"相信日志持有者"的基础上。

对于金融、医疗、受监管研究等合规场景,这种"事后可以赖账"的日志远远不够。你需要的是第三方无需信任你即可独立验证的防篡改证据

方案总览:策略门控 + 签名回执 + 离线验证

protect-mcp用三个技术支柱补齐上述缺口:

  • Cedar 策略:每个工具调用在执行前都先经过 Cedar 策略评估,deny是权威性的,命中即拦截;
  • Ed25519 签名回执:每次 allow/deny 决策都会生成包含输入、治理策略与结果的回执,回执之间通过parent_receipt_id哈希链式相连,插入、删除、修改均可被检测;
  • 离线验证npx @veritasacta/verify纯本地运行,无需服务器、无需账号、无需信任运营方,可在断网(air-gapped)环境工作。

整体数据流在 plugins/protect-mcp/README.md 中描述为一条完整流水线:工具调用 →PreToolUse钩子做 Cedar 求值(permit 放行 / deny 以 exit 2 拦截)→ 工具执行 →PostToolUse钩子生成 Ed25519 签名回执写入./receipts/<timestamp>.json

快速接入:四步完成项目治理

在项目根目录执行以下操作即可启用:

# 1. 安装插件(向项目注入 hooks 与 skill) claude plugin install wshobson/agents/protect-mcp # 2. 在 .claude/settings.json 中配置 hooks(见下文) # 3. 启动回执签名服务(本地运行,无外部调用) npx protect-mcp@latest serve --enforce # 4. 正常使用 Claude Code,每个工具调用都会被策略评估, # 并在 ./receipts/ 下生成签名回执

说明:serve --enforce以强制模式启动本地签名服务;SKILL.md 中的示例使用@latest,而仓库内 hooks/hooks.json 固定为@0.7.4,实际接入时建议锁定版本以保证可复现性。

钩子配置:PreToolUse 拦截 + PostToolUse 签名

SKILL.md 给出的最小配置如下,写入项目.claude/settings.json

{ "hooks": { "PreToolUse": [ { "matcher": ".*", "hook": { "type": "command", "command": "npx protect-mcp@latest evaluate --policy ./protect.cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" || exit 2" } } ], "PostToolUse": [ { "matcher": ".*", "hook": { "type": "command", "command": "npx protect-mcp@latest sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts ./receipts/" } } ] } }

每个钩子做什么

  • PreToolUse(工具执行前):对工具调用进行 Cedar 策略评估。若策略返回deny,钩子以退出码 2 结束,Claude Code 会完全拦截该工具调用。
  • PostToolUse(工具执行后):为已完成的操作签名,回执包含工具名、输入哈希、输出哈希、决策结果、策略摘要与时间戳,写入./receipts/<timestamp>.json

仓库内 hooks.json 的进阶配置项

实际随插件分发的 hooks/hooks.json 比 SKILL.md 示例更完整,引入了三个可通过环境变量覆盖的配置点:

{ "hooks": { "PreToolUse": [ { "matcher": ".*", "hooks": [ { "type": "command", "command": "npx protect-mcp@0.7.4 evaluate --policy \"${PROTECT_MCP_POLICY:-./protect.cedar}\" --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --fail-on-missing-policy false" } ] } ], "PostToolUse": [ { "matcher": ".*", "hooks": [ { "type": "command", "command": "npx protect-mcp@0.7.4 sign --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\" --output \"$TOOL_OUTPUT\" --receipts \"${PROTECT_MCP_RECEIPTS:-./receipts/}\" --key \"${PROTECT_MCP_KEY:-./protect-mcp.key}\"" } ] } ] } }

逐项解读:

配置点默认值作用
PROTECT_MCP_POLICY./protect.cedar指定 Cedar 策略文件路径,不设置则使用项目根目录默认文件
PROTECT_MCP_RECEIPTS./receipts/回执输出目录
PROTECT_MCP_KEY./protect-mcp.key签名私钥文件路径,用于 Ed25519 签名
--fail-on-missing-policy false策略文件缺失时不阻断调用,避免误伤开发流程(SKILL.md 示例未包含此开关)
matcher: ".*"匹配全部工具名,确保 Bash/Edit/Write/Read/WebFetch 等一律纳入治理

可以看到,sign命令额外暴露了--key参数,说明回执签名使用项目级密钥而非全局密钥,不同项目可持有各自的签名身份。

编写 Cedar 策略:允许清单与禁止规则

在项目根目录创建./protect.cedar。SKILL.md 给出的基线策略演示了三类规则写法:

// 默认放行只读类工具 permit ( principal, action in [Action::"Read", Action::"Glob", Action::"Grep", Action::"WebFetch"], resource ); // 对破坏性工具要求显式放行:仅允许安全命令 permit ( principal, action == Action::"Bash", resource ) when { // 仅放行安全命令 context.command_pattern in ["git", "npm", "ls", "cat", "echo", "pwd", "test"] }; // 永远禁止递归删除 forbid ( principal, action == Action::"Bash", resource ) when { context.command_pattern == "rm -rf" }; // 禁止对项目目录之外的文件执行写入,必须二次确认 forbid ( principal, action in [Action::"Edit", Action::"Write"], resource ) when { context.path_starts_with != "." };

要点:

  • permitforbid成对出现:对高风险动作既写带条件的permit,又写覆盖明显危险用例的forbid。Cedar 语义下forbid命中即权威,即使存在匹配的permit也一律拒绝;
  • context携带工具输入特征Bashcontext.command_pattern匹配命令族(git/npm/ls 等),Edit/Writecontext.path_starts_with限定文件系统作用域;
  • 注释即文档:策略是安全关键配置,每条规则都应以注释说明意图与所针对的威胁模型。

策略实际求值时的实体形状(重要实现细节)

SKILL.md 中的示例为了可读性使用了简化写法(如Action::"Read")。而仓库测试夹具 test/fixtures/test-policy.cedar 的注释明确指出:protect-mcp ≥ 0.7.0 实际求值时使用的实体形状是

  • principal Agent::"<id>"——调用方是 Agent 实体;
  • action Action::"MCP::Tool::call"——动作统一收敛为一次"工具调用",而不是每种工具一个 Action;
  • resource Tool::"<toolName>"——资源是具体工具名(如Tool::"Read"Tool::"Bash");
  • 工具入参放在context.input中。

对应的真实求值策略形如:

// 放行只读类工具 permit ( principal, action == Action::"MCP::Tool::call", resource ) when { resource == Tool::"Read" || resource == Tool::"Glob" || resource == Tool::"Grep" || resource == Tool::"WebSearch" }; // Bash 仅放行安全命令前缀 permit ( principal, action == Action::"MCP::Tool::call", resource == Tool::"Bash" ) when { context has input && context.input has command && (context.input.command like "git*" || context.input.command like "npm*" || context.input.command like "ls*" || context.input.command like "cat*" || context.input.command like "echo*" || context.input.command like "pwd*" || context.input.command like "node*") }; // 对破坏性命令显式拒绝,Cedar forbid 权威 forbid ( principal, action == Action::"MCP::Tool::call", resource == Tool::"Bash" ) when { context has input && context.input has command && (context.input.command like "*rm -rf*" || context.input.command like "dd *" || context.input.command like "*mkfs*" || context.input.command like "*shred*") };

注意这里命令匹配使用like通配符(如"git*")作用于context.input.command,与 SKILL.md 中基于context.command_pattern集合包含的写法形态不同,这正是新旧求值语义差异的体现——接入时请以你所用protect-mcp版本实际求值的实体形状为准(可先对照仓库测试策略验证行为,再投入生产)。

三种场景的成熟策略模板

agents/policy-enforcer.md(Cedar 策略编写 Agent,推荐 Opus 模型)提供了按风险画像划分的三档模板,可直接演化:

  1. 研究型项目(只读安全)permit全部只读工具 +WebSearchforbid覆盖Write/Edit/Bash/WebFetch
  2. 开发型项目(受限写入):只读放行;Write/Edit仅在context.path_starts_with == "./"时放行;Bash白名单扩展到git/npm/pnpm/yarn/ls/cat/pwd/echo/test/node/python/makeforbid覆盖rm -rf/dd/mkfs/shred
  3. 生产部署(严格显式授权):所有动作按context.trust_tierevidenced/institutional)分级放行,Write仅限./deployments/./config/Bash仅限kubectl applyterraform planterraform apply,最后用兜底forbid拒绝一切未授权动作。

编写完成后建议用cedar validate做类型检查(若项目带 Cedar schema),并对照政策 Agent 提供的审计清单逐条复核:是否存在已知危险操作缺少forbid、是否存在无when条件的过度宽泛permitEditWrite的放行是否一致、是否存在逻辑缝隙。

签名回执格式与密码学基础

每次决策产生一个 JSON 回执,结构如下(来自 SKILL.md):

{ "receipt_id": "rec_8f92a3b1", "receipt_version": "1.0", "issuer_id": "claude-code-protect-mcp", "event_time": "2026-04-15T10:30:00.000Z", "tool_name": "Bash", "input_hash": "sha256:a3f8...", "decision": "allow", "policy_id": "autoresearch-safe", "policy_digest": "sha256:b7e2...", "parent_receipt_id": "rec_3d1ab7c2", "public_key": "4437ca56815c0516...", "signature": "4cde814b7889e987..." }

agents/receipt-verifier.md 给出了更严格的字段规约:receipt_idrec_<hash>decision仅允许allowdenypolicy_digest/input_hashsha256:<hex>public_key为 64 位十六进制(32 字节公钥);signature为 128 位十六进制(64 字节签名);首个回执的parent_receipt_idnull

回执的四个密码学属性:

  • Ed25519 签名(RFC 8032):确定性、高性能、安全性经过充分研究的 Edwards 曲线签名方案;
  • JCS 规范化(RFC 8785):签名前对 JSON 按键字典序排序得到确定性字节序列。因为同一份 JSON 有多种合法序列化方式,规范化是签名可复现验证的前提;
  • 哈希链(Hash Chain):通过parent_receipt_id指向前一张回执,形成"有页码的账本"——撕页、插页都能被发现;
  • 离线可验证:验证不依赖任何网络调用或厂商查询。

理解回执时可以参考 agents/receipt-verifier.md 中的三个类比:签名如同信封上的火漆印,任何人可核对寄件人,信封被拆过封印即破损;JCS 规范化如同封口前把字词按字母序排列,使封印模式可预测;哈希链如同有编号的账页,页码跳号即证明有人撕过页。

验证:单张回执与整链审计

验证单张回执

npx @veritasacta/verify receipts/2026-04-15T10-30-00Z.json # Exit 0 = 有效 # Exit 1 = 被篡改 # Exit 2 = 结构畸形

验证整条链:

npx @veritasacta/verify receipts/*.json

配合 commands/verify-receipt.md 的实现说明,@veritasacta/verify内部执行六步:读取 JSON → 校验结构(必填字段与类型)→ 提取公钥与签名 → 重建 JCS 规范化形式 → 对规范化字节做 Ed25519 验签 → 输出结果。三个退出码的语义在 agents/receipt-verifier.md 中有完整映射:

退出码含义处置建议
0签名有效、结构规范报告 "Verified. Receipt authentic."
1签名与载荷不匹配,回执被改动报告 "TAMPERED",提示与已知完好副本比对定位被改字段
2缺少必填字段或类型错误报告 "MALFORMED",列出结构性问题(可能签名器有 bug 或伪造者不懂格式)

常见失败原因的精确诊断:签名不匹配说明签名后任一受签字段被修改;链断裂parent_receipt_id与前一回执receipt_id不符)可能意味着插入、删除或链分叉;畸形则是结构层面问题。注意:验证失败时不要臆断,而是先检查对应回执文件是否确实存在、顺序是否按event_time排序。

在 Claude Code 内使用斜杠命令

SKILL.md 提供了两个内置命令,分别对应 commands/verify-receipt.md 与 commands/audit-chain.md:

/verify-receipt receipts/latest.json /audit-chain ./receipts/ --last 20

/audit-chain支持三个形态:

  • /audit-chain——校验./receipts/下全部回执;
  • /audit-chain --last 50——只校验最近 50 张;
  • /audit-chain --dir /var/log/receipts——指定其他回执目录。

其内部流程是:列出目标目录全部*.json→ 按event_time排序建立时间序 → 逐张独立验签 → 核对parent_receipt_id与前一张receipt_id是否衔接 → 输出诊断。链级校验还可显式启用--chain标志:npx @veritasacta/verify --chain "$RECEIPT_DIR"/*.json。诊断输出会区分两种失败模式:链断裂(个体签名全部有效但结构被破坏,多为插入/删除攻击)与单张被篡改(链链接完好但某张签名不通过,多为事后改载荷)。

建议在以下时机执行整链审计:发布前确认开发链无篡改;安全审计时向审计方证明链完整性;事件响应后确认日志未被动手脚;周期性 CI 任务捕获静默损坏;合规评审前提供连续性完整性证据。

测试保障:从策略求值到防篡改回归

仓库在 test/ 下内置了完整的往返测试(round-trip)体系,验证"evaluate → sign → verify"全链路,包括篡改检测路径。夹具设计如下:

  • test/fixtures/test-policy.cedar——统一测试策略(即上文真实实体形状示例);
  • test/fixtures/pretool-allow-read.json——Read应被放行;
  • test/fixtures/pretool-allow-bash-safe.json——Bash git status应被放行(context.command_pattern: "git");
  • test/fixtures/pretool-deny-bash-destructive.json——Bash rm -rf /应被拒绝(context.command_pattern: "rm -rf");
  • test/fixtures/pretool-deny-write.json——Write应被拒绝;
  • test/expected/receipt-schema.json——回执的期望 JSON Schema。

运行完整往返测试(需 node ≥ 18、npx、python3):

./run-tests.sh

首跑会从 npm 拉取protect-mcp@veritasacta/verify,随后执行八个场景:

#场景期望退出码
1PreToolUse作用于Read0(放行)
2PreToolUse作用于Bash git status0(放行)
3PreToolUse作用于Bash rm -rf /2(拒绝)
4PreToolUse作用于Write2(拒绝)
5PostToolUse签名生成回执文件0(成功)
6生成回执符合 Schema0(有效)
7@veritasacta/verify接受该回执0(有效)
8被篡改的回执被拒绝1(被篡改)

其中测试 8 是关键的回归防线:翻转已签名回执中的decision字段必须导致 Ed25519 验签失败,@veritasacta/verify必须退出 1 而非 0——这直接证明"签名锁定载荷"的防篡改承诺成立。

另有一个 CI 友好的静态校验脚本,仅需 python3、无网络调用:

./verify-fixtures.sh

它逐份校验夹具是否为合法 JSON 且结构符合预期,适合沙箱或离线 CI。两个脚本均遵循 autotools 惯例:退出码 77 表示"依赖缺失跳过",多数 CI 框架会将其解释为 skip。

从"信任"到"可证明":治理范式转变

SKILL.md 用一张对照表总结了接入前后的本质变化:

接入前接入后
"相信我,Agent 只读了文件"密码学可证明:每次 Read 都被记录并签名
"日志显示它发生了"回执证明它发生了,且任何人都无法编辑
"你得审计我们的系统"任何人都能离线验证每一张回执
"日志现在可能已经变了"Ed25519 签名在签名时刻锁定记录

标准与技术栈一览

  • Ed25519—— RFC 8032 数字签名,回执签名算法;
  • JCS—— RFC 8785 确定性 JSON 规范化,签名前对载荷做规范化处理;
  • Cedar—— AWS 开源授权策略语言,策略求值引擎,deny权威;
  • IETF draft-farley-acta-signed-receipts—— 签名回执协议的互联网草案,定义回执字段规约。

配套资源集中在仓库内:安装与总览见 plugins/protect-mcp/README.md,完整接入指南即本文骨架 skills/protect-mcp-setup/SKILL.md,真实钩子配置见 hooks/hooks.json,策略编写与审计交给 agents/policy-enforcer.md,回执验证与诊断交给 agents/receipt-verifier.md,测试体系见 test/README.md。项目本身是一个面向 Claude Code、Codex、Cursor、OpenCode、GitHub Copilot、Google Antigravity 等多载体(multi-harness)的 Agentic 插件市场,protect-mcp是其中负责"合规级审计证据"能力的一环。

【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询