区块链(22):签名域正确仍会发生业务重放
一个“同意释放订单 70”签名即使通过 EIP-712 的结构化消息校验,也可能被原样提交两次。结构化域通常包括协议名、版本、链 ID、验证合约等;它降低消息与另一应用或网络被误用的风险,却不自动提供业务 nonce、截止时间或撤销表。这些字段及其持久化消费条件由托管应用自己决定。
先修区块链(21):ABI、数据位置与事件各承诺什么与区块链(03):签名证明授权了哪条消息。授权消息至少绑定订单 ID、具体动作、金额、授权者、单次消费标识和期限;合约先检查签名者身份和当前角色、订单状态、域与截止,再在同一状态迁移中消费 nonce,随后安排款项领取。即使签名有效,卖家也不能用买家的签名跨另一个合约、另一笔订单或不同数额提款。
flowchart TD
M[domain + typed orderId/action/amount/nonce/deadline] --> S[校验签名者]
S --> A[角色和订单状态]
A --> D[链/合约/期限正确?]
D --> N[nonce 未使用? 原子消费]
N --> C[状态变化或债权登记]
权限矩阵不能只列正常买卖方,还要覆盖部署者、被删除的角色、已关闭订单及签名仍在链外传播的旧授权。管理员改域版本时,旧签名究竟失效还是保留需明确迁移规则;升级合约但不更新域/nonce 存储可能带来跨版本重放。
一份相同签名对应四种失败
授权者批准“在链 A 的托管 X,订单 17 最多释放 70,截止某个界限、nonce=4”。签名字节只证明持钥方对特定类型化摘要签名:把签名发到托管 Y 或链 B 时,若域确实纳入 X/A 应拒绝;把订单改为 18 或金额改为 71 应因消息体不匹配而拒绝;原样重放到同一 X/A 时密码学验证仍可能通过,必须由合约中已消费 nonce 和订单状态拒绝;超过截止条件时即使仍未消费也须拒绝。四条拒绝路径各涉及不同的信任根,不能用一条“bad signature”测试全包。
签名检查的顺序也不应忘记角色:买方可以确认交付,并不等于部署者或者链下转发人继承买方权限。若系统存在轮换管理员或撤销授权,签名在转发队列中等待时要根据执行时的规则判定;完成付款之后仍保留的签名不得恢复一笔已经终结的订单。代理升级若改变 EIP-712 域版本或迁移 nonce 集合,还需回答旧授权的处理策略。当前缺少可部署的合约,以上是授权矩阵与反例,不是本系列已经完成的 EIP-712 向量验证。
练习一:同一签名第二次提交,验签仍然能通过吗?答案:字节没变通常仍能验签,应用必须因 nonce 已消费或状态终结而拒绝。练习二:把 chainId 或验证合约地址换掉、重新计算结构化消息哈希,旧签名能直接通用吗?答案:不应通用;若域缺失这些绑定则需额外防线。当前无真实合约环境,错链/错合约/过期/重复矩阵 NOT_RUN。
可迁移原则:密码学可证明签署过,业务还要消费一次性授权。参考:EIP-712、OpenZeppelin EIP712 接口(release、源码 SHA 与实际行为待核);导航:区块链(21):ABI、数据位置与事件各承诺什么 · 22 · 区块链(23):外部调用前后的资产账本怎样保持一致。






