Havenlon|执行缝隙(十):审批、签名和执行,为什么不是同一件事 📅 2026/7/13 14:43:08 审批回答的是谁同意。签名回答的是谁确认。执行回答的是现实是否被改变。写在前面这是执行缝隙系列的第十篇也是面向工程读者的一篇。如果你是做后端、做安全、做区块链、或者正在给业务系统接 AI Agent 的开发者这篇想跟你聊一个在架构里几乎被默认、却很少被显式建模的问题在我们的系统里审批通过、签名完成、执行成功这三个状态是不是被当成了同一件事很多系统的执行链路本质上是这样一条隐式状态机approved true → signed true → executed true → ✅ 安全它把三个不同层次的布尔值串成了一条默认放行链fail-open pipeline只要前一个为真后一个就自动往下走最后一个为真就宣布闭环。本文想论证的是这条链在高风险场景下是错的。审批、签名、执行属于三个不同的语义域回答的是三个不同的问题必须被拆开、被分别校验、并在执行前重新绑定。摘要很多系统会把审批、签名和执行混在一起理解审批通过了就认为可以执行签名完成了就认为执行安全多签达成了就认为风险已经被控制系统返回成功了就认为整个流程没有问题。但在高风险执行系统里这三件事必须被拆开审批Approval是治理动作发生在组织流程里签名Signature是确认动作发生在身份与数据的关系里执行Execution是现实动作发生在真实世界里。它们彼此相关但不是同一件事。如果系统把审批当成执行安全把签名当成真实意图把执行当成流程的自然结果就会产生一个危险的幻觉只要流程完整现实就应该发生。但现实不是流程的附属品。现实一旦被改变——资金转出、权限打开、数据删除、设备动作、链上交易广播——很多状态就已经不可逆。所以执行系统必须重新区分三个问题而且这三个问题不能由同一个机制来回答审批有没有通过签名有没有完成执行应不应该发生一、审批解决的是治理问题Governance审批的核心价值是让高风险动作进入组织治理。它让一个动作不再由单个人直接决定让不同角色参与判断让责任链清晰让流程可追溯让组织能够表达我们是否同意这件事。所以审批很重要企业付款、权限变更、运维变更、资产转移、Agent 高风险工具调用、生产系统操作都需要审批。但审批解决的是治理问题。它回答的是这个请求是否经过了规定的人和规定的流程它不天然回答另一个问题最终执行的那个动作是否仍然安全审批人看到的通常是摘要、页面、申请理由、风险等级、附件、Agent 解释或业务说明。审批人批准的是他看到的那个版本。而最终执行可能已经经过了参数转换、策略匹配、payload 生成、任务调度、签名确认、外部接口调用。用一句话总结审批通过只能证明治理链路通过它不能自动证明真实执行安全。从访问控制模型看审批本质上是一个PDPPolicy Decision Point策略决策点的产物——它输出一个决定,而决定和决定被正确执行,是两回事。二、签名解决的是确认问题Authentication / Integrity签名的核心价值是把某个主体和某段数据绑定起来。它证明某个密钥确认过这段数据某个设备参与过这次确认某个身份对某个 payload 做过授权某个多签组合达成过阈值某个请求在签名后没有被篡改。在 Web3、企业密钥体系、设备认证、API 安全、硬件确认里签名都是基础能力。它同时提供了两个密码学属性身份authentication和完整性integrity——数据是谁签的签完有没有被改。但签名解决的是确认问题。它回答的是这段数据是否被某个主体确认过它不天然回答这段数据是否应该被确认,更不天然回答这段数据是否仍然对应最初的 Intent。如果 payload 本身就是错的签名仍然有效如果用户看到的摘要和 payload 不一致签名仍然有效如果多签成员共同确认了错误对象多签仍然有效如果 Agent 生成了语义漂移的 payload签名仍然有效。这就是盲签blind signing的本质困境签名保证了sign(sk, payload)在密码学上成立却完全不关心payload在语义上是否等于用户想要的东西。签名只能证明谁确认了什么数据,它不能证明这个数据代表的动作是否应该发生。所以签名不是执行安全的终点。它是必要条件不是充分条件。三、执行解决的是现实问题Enforcement执行和审批、签名完全不同。审批还停留在流程里签名还停留在数据上而执行会改变现实资金真的转出、权限真的开通、数据真的删除、服务真的发布、设备真的动作、合约真的调用、Agent 真的访问了外部系统、生产环境真的被改变。执行不是一个记录不是一个确认不是一个意愿表达。执行是现实状态的变化。这也是执行最危险的地方因为它常常是不可逆的irreversible审批错了还可能被拦在后续流程里签名错了只要还没广播还可能停下来但执行错了很多时候已经越过了提交点point of no return。所以执行不能只是审批和签名的自然延伸。执行前必须有一次独立判断即使审批通过了即使签名完成了——这个动作现在是否仍然应该发生在访问控制模型里这对应PEPPolicy Enforcement Point策略执行点。而本系列反复强调的一点是PDP ≠ PEP出决定的地方和拦动作的地方必须是两个独立的组件。四、三者混在一起会制造安全幻觉很多系统的问题不是没有审批也不是没有签名。恰恰相反它们审批完整、签名完整、日志完整。问题在于它们把三者混成了一件事。审批通过被理解成执行安全签名完成被理解成真实意图执行成功被理解成流程正确。于是系统形成了一个线性假设approved → signed → executed → 安全闭环但真实系统不是线性的审批通过之后请求可能变化签名完成之前payload 可能已经语义漂移签名完成之后执行上下文可能变化执行发生之后结果可能已经超出原始意图。所以更准确的模型应该是审批是治理信号签名是确认信号执行是现实动作——三者之间必须被持续绑定并重新校验而不是自动串联。没有绑定审批、签名、执行就只是三个局部正确的节点。而在分布式系统里我们都知道一件事局部正确不等于整体正确。五、审批通过不代表签名对象正确审批发生时人看到的是某个版本的请求付款申请、权限申请、运维工单、Agent 行动计划、交易摘要、SaaS 任务说明。审批通过后系统会把它转换成更具体的执行对象。这个转换过程会产生错位。审批看到的人类语义层签名/执行对象机器 payload 层一笔付款另一组支付参数收款账户被改临时权限包含长期授权的 scope测试环境变更指向生产环境的 targetAgent 的自然语言计划Agent 动态生成的 tool call这时候审批通过是真的但签名对象不一定正确。如果系统只校验approval_id 是否存在却不校验审批内容 ≟ 签名对象的语义一致性执行缝隙就出现了。审批和签名之间必须有绑定否则审批只是流程记录,签名只是数据确认两者从未证明过它们指向的是同一个动作。六、签名完成不代表执行对象仍然安全签名完成后很多系统会直接进入执行。简单场景下这没问题但复杂系统里签名之后仍可能发生变化执行时间延迟、外部状态变化、策略版本变化、目标对象变化、风险等级变化、Agent 上下文变化、任务队列重排、第三方系统返回新状态。同一个签名对象在不同上下文下执行后果可能完全不同签名时目标账户正常执行时账户已被冻结/异常签名时环境是测试执行时任务被路由到生产签名时权限是临时操作执行时组合成了长期访问签名时 Agent 计划合理执行时 Agent 已调整了工具路径。这就是经典的TOCTOUTime-Of-Check to Time-Of-Use问题——检查的时刻和使用的时刻之间世界变了。签名是历史确认执行是当前发生。历史的确认不能自动覆盖当前的风险。所以执行前仍需重新校验当前上下文。顺带一提签名如果没有和一次性 nonce / 幂等键绑定还会引入重放replay风险同一个签名被拿去执行两次。绑定必须是(intent, context, nonce)三元组用过即失效。七、执行成功不代表前面的语义正确很多系统把执行成功当成流程正确的证明接口返回 200、交易广播成功、任务完成、权限同步成功、设备响应成功、Agent 工具调用成功。但执行成功只说明系统完成了动作不说明这个动作应该发生。一笔错误付款可以执行成功一次错误授权可以执行成功一次错误删除可以执行成功一次错误部署可以执行成功一笔错误交易可以链上成功一次错误的 Agent 工具调用也可以返回成功。成功是系统状态正确是语义关系。二者不在同一个维度上。执行系统不能把成功执行等同于安全执行。最危险的错误往往不是执行失败而是错误的动作被顺利执行——它不报错不告警日志里一片干净。八、AI Agent 会让三者更容易混淆AI Agent 时代审批、签名、执行之间的边界会更模糊。因为 Agent 会把用户目标拆成计划把计划变成 tool call把 tool call 变成 payload把 payload 送进系统——这是一条自动化的转换链。于是三者常常不在同一层对象上用户审批的 帮我完成这个任务 # 自然语言 / 目标层 签名确认的 callTool(api, {params...}) # payload 层 执行发生的 外部系统状态被改变 # 现实层如果没有独立绑定系统很容易得出三个错误的等式同意 Agent 的计划同意所有后续 tool callAgent 生成了 payloadpayload 符合用户意图tool call 返回成功任务安全完成。这正是 AI Agent 放大执行缝隙的根本原因它把审批、签名、执行之间的转换自动化了。自动化程度越高就越需要显式的边界。因为人一旦退出链路中间就再没有任何一个环节会替你追问这还是我要的吗。九、Web3 最典型的错误把签名当成执行安全Web3 世界里签名非常重要但它的很多风险恰恰来自把签名当成了最终安全边界。用户签了、多签够了、交易合法、链上执行成功——于是系统认为风险闭环。但真正该问的是用户签的 payload是否符合用户真实意图钱包展示是否和合约后果一致多签成员是否理解真实的权限变化签名之后是否还有最后的拒绝能力链上执行是否已经不可逆链只负责执行合法交易。它不判断用户是否理解不判断 UI 是否诚实不判断审批是否被诱导不判断 payload 是否语义正确。签名可以证明授权但不能证明执行安全。在不可逆的链上执行场景里签名之后仍然需要执行控制。一个经典反例approve(spender, amount)。用户以为在确认一次交易,而amount被设为uint256最大值——签名有效、交易合法、链上成功一次无限额度授权就此不可逆地生效。十、企业系统最典型的错误把审批当成执行控制企业系统里常见错误是把审批流当成安全边界只要审批通过系统就自动执行。付款审批通过 → 进支付接口权限审批通过 → 进 IAM变更审批通过 → 进 CI/CD工单审批通过 → 进自动化脚本Agent 请求通过 → 进 tool call。这套逻辑看起来很顺但审批流本质上是治理系统不是执行控制系统。它擅长管理流程却不一定擅长验证 payload、不一定理解外部后果、不一定检查当前上下文、不一定能在执行前拒绝、不一定能证明审批对象与执行对象一致。所以企业系统真正要补的不是更多审批按钮而是审批之后、执行之前的那道边界。审批可以给出 yes但执行边界必须还能说 no。十一、三者应该如何正确分工审批、签名、执行不是互相替代关系它们应该分工并组织成一条证据链。审批负责治理Governance谁发起、谁同意、为什么同意、在什么条件下同意、同意范围是什么、审批是否有效。签名负责绑定Binding / Integrity谁确认、确认了哪个 payload、payload 是否被篡改、签名是否来自合法设备或密钥、确认是否可验证。执行负责现实裁决Enforcement当前状态是否仍然允许、payload 是否符合 Intent、审批对象是否和执行对象一致、策略是否仍然成立、动作是否越界、后果是否可接受、是否应该允许发生、是否需要拒绝。用伪代码把这道执行门execution gate显式化大概是这样def execution_gate(request) - Decision: # 上游信号只是 输入不是 结论 approval get_approval(request.approval_id) signature verify_signature(request.payload) # AuthN Integrity intent load_signed_intent(request.intent_ref) # 起点意图凭据 # 1) 三者必须指向同一个对象语义级而非仅 ID if not semantically_equal(intent, request.payload): return DENY(intent/payload mismatch) if not semantically_equal(approval.object, request.payload): return DENY(approval/execution mismatch) # 2) 当前上下文必须重新求值对抗 TOCTOU if not policy.reevaluate(request, ctxcurrent_context()): return DENY(policy no longer holds) # 3) 一次性防重放 if nonce_used(request.nonce): return DENY(replay) # 4) 拿不准就拒绝fail-closed if not can_prove_safe(request): return DENY(cannot prove safety) consume(request.nonce) return ALLOW这段伪代码里有几个工程细节值得单独强调。第一semantically_equal不是hash_equal。字节相等只能抓住篡改抓不住合法重编码里夹带的语义偏移——字段顺序变了、编码方式变了哈希就变了,但语义没变;反过来,一个地址改了最后几位,语义天翻地覆,哈希差异却可能被淹没在一堆参数里。所以这一步必须把 payload 解析回语义,逐项比对对象、额度、范围、可逆性。第二policy.reevaluate用的是current_context()不是审批时缓存下来的旧上下文。这是对抗 TOCTOU 的关键:决策必须发生在离执行最近的时刻。第三整个函数的默认分支是DENY。任何一个if没能明确证明安全,都会掉进fail-closed的兜底。在高风险执行里,拿不准的正确答案是不,而不是先放过去。把这三层能力对应到经典的安全模型,其实非常清晰:层安全语义回答的问题对应机制审批Authorization授权/治理谁被允许PDP签名Authentication Integrity谁确认的数据动没动密钥 / 多签执行Enforcement强制执行现在到底该不该发生PEP / 执行控制层绝大多数系统把前两层做得很厚,却几乎没有独立的第三层——它们默认授权 确认 可以执行。而执行缺陷,恰恰住在这个被省略的第三层里。关键不在代码细节而在这个函数存在的位置它必须独立于生成 request 的那些系统。审批不能替代签名签名不能替代执行执行不能盲目信任审批和签名。它们必须被组织成一条证据链而不是一条自动放行链。十二、Havenlon 的价值把三者重新拉开Havenlon 要解决的不是没有审批或没有签名的问题。而是审批、签名、执行在很多系统里被混成了一条默认放行链。Havenlon 要做的是把它们重新拉开——让审批、签名、策略、SaaS、Agent 请求、payload全部退回到输入input的位置而把是否执行交给一个独立的裁决最终是否执行需要一次独立裁决。它不能完全属于 SaaS不能完全属于审批按钮不能完全属于签名设备不能完全属于 Agent也不能完全属于上游业务系统。它必须在现实发生之前重新回答那一个问题这个动作现在是否仍然应该发生如果不应该——拒绝。而且这道裁决要落在硬件里满足参考监视器reference monitor的三条要求完全仲裁每个高风险动作都过它、防篡改上游软件无法绕过、可验证逻辑小到能被审计。这就是执行控制层的意义。结语审批、签名和执行不是同一件事。审批表达组织同意签名确认某段数据执行改变现实状态。审批通过不代表签名对象正确签名完成不代表执行对象安全执行成功不代表语义正确。过去的软件系统习惯把这三者串成一条顺滑的流程。但 AI Agent、企业自动化、Web3 多签和跨系统执行会让这条流程中间裂开越来越多的缝隙。真正的安全不是让审批、签名、执行自动连成一条放行链而是让它们彼此绑定、彼此校验、彼此限制。尤其在现实发生之前系统必须保留最后一个问题即使审批通过了即使签名完成了——这个动作真的还应该执行吗这就是 Havenlon 要守住的地方。它不否定审批不否定签名也不否定自动化执行。它只是拒绝把三件不同的事误认为同一个安全事实。因为高风险系统里最危险的错误就是这样一句话流程上每一步都对现实里却发生了错的事。本文是执行缝隙系列第十篇。如果你正在为业务系统接入 AI Agent、或在设计高风险动作的执行链路欢迎在评论区聊聊你们是怎么区分approved / signed / executed的——尤其是你们的系统里有没有那个能在最后一刻说 no 的独立边界。