Mind·Quality
payment-research · 04

盲签(Blind Signing)详解 + 攻击/防御时序图

解释盲签风险,并用攻击与防御时序图说明如何降低不可逆损失。

公开研究2026.07

2026-07-08 | 针对 x402 类稳定币支付的最大盲区

一、什么是盲签?

盲签 = 在"看不懂/没解码"签名内容的情况下就签名授权。

x402 付款时,客户端要签一笔 EIP-3009 transferWithAuthorization 消息。这条消息本质是一串结构化数据(EIP-712),字段包括:

字段 含义 攻击者可做的手脚
to 收款地址 换成攻击者地址
value 转账金额 402 显示 1 USDC,实际让你签 10000
validAfter/validBefore 有效期 拉长有效期便于后续利用
nonce 防重放随机数 ·
chainId / domain 链与合约域 换成别的链/合约

盲签的危险:钱包/Agent 只显示"请签名"或一串十六进制,用户/Agent 看不到真实的 tovalue 就点了同意。 攻击者于是可以: - 金额调包:界面说 1 USDC,签的却是天价; - 地址调包:钱打给攻击者而非商家; - 消息类型调包:更狠的是根本不是 transferWithAuthorization,而是 approve/permit 这类授权额度消息 · 一旦签下,攻击者可反复把你钱包掏空,不止一笔。

一句话:盲签 = 把一张空白支票签了名递出去。 破解之道就是"签之前先把支票内容打印出来看清楚" · 即解码 + 白名单校验


二、攻击 vs 防御 对照时序图

sequenceDiagram
    autonumber
    participant Agent as AI Agent / 钱包
    participant Guard as 安全校验层<br/>(解码+白名单)
    participant Evil as 恶意服务器
    participant Chain as 链上 (USDC 合约)

    Agent->>Evil: GET /resource
    Evil-->>Agent: 402 显示"仅需 1 USDC"<br/>但内嵌授权是: to=攻击者, value=10000

    alt ❌ 盲签路径(危险)
        Agent->>Agent: 不解码, 直接签"请求签名"
        Agent->>Chain: 广播 EIP-3009 授权
        Chain-->>Evil: 10000 USDC 转给攻击者
        Note over Agent,Chain: 不可逆, 无退款, 损失已成
    else ✅ 验签路径(防御)
        Agent->>Guard: 提交待签消息, 请求校验
        Guard->>Guard: 解码 EIP-712:<br/>读出真实 to / value / chainId
        Guard->>Guard: 比对: value==402声明? 地址∈白名单? ≤预算?
        Guard-->>Agent: ⚠️ value=10000 ≠ 声明1, 地址不在白名单 → 拒签
        Agent->>Evil: 中止, 不签名, 零损失
    end

三、防御清单(把盲签堵死)

  1. 强制解码展示:签名前必须解出 EIP-712 的 to / value / chainId / 消息类型,展示给人或让 Guard 校验。
  2. 消息类型白名单:只允许 transferWithAuthorization,拒绝 approve/permit 等无上限授权。
  3. 收款地址白名单:to 必须 ∈ 已知可信商家地址。
  4. 金额一致 + 上限:value 必须 == 402 声明金额,且 ≤ 预算硬顶。
  5. 链/合约核对:chainId 与 USDC 合约地址是预期的。
  6. 有效期最小化:validBefore 尽量短,减少被利用窗口。
  7. 独立低额度钱包:即便被骗,损失被账户额度封顶。

四、一句话总结

盲签就是"没看清就签授权";x402 里它能被用来改金额、改收款人、甚至签成掏空钱包的额度授权。 防御核心极简:签前解码 → 比对(类型/地址/金额/链)→ 不符就拒签。这一步把"空白支票"变成"看清金额的支票"。