盲签问题解决了?Clear Signing今日上线

Cyfrin 发布于 2026-05-13 阅读 127

本文介绍了Clear Signing——一个开放标准,旨在解决以太坊交易中的“盲签”问题,即用户签署无法理解的交易数据,导致Bybit(15亿美元被盗)等安全事件。

Travis Montgomery

盲签 - 解决了吗?

盲签从 Bybit 盗走了 15 亿美元。Clear Signing 今天作为解决这一问题的开放标准推出 — 以下是 Cyfrin 发布的内容以及下一步的工作方向。

盲签 - 解决了吗?

今天,Clear Signing — 一项使以太坊交易对授权者来说可读的开放标准 — 在以太坊基金会的万亿美元安全倡议下作为中立托管方开始运作。此次发布包含更新后的 ERC-7730、一个可供任何人镜像的 EF 托管注册表、一个 ERC-8176 证明框架、由 Cyfrin 撰写的 ERC-8213 字节级后备方案,以及来自多供应商工作组的开发者库。

Cyfrin 是贡献者之一。本文介绍了我们为此次发布所构建的内容,为什么这个问题一直是我们的优先事项,以及我们接下来的发展方向。

今天发布的内容

此次发布并非一个单一项目 — 而是四个相互协同的基础设施组件:

  1. ERC-7730 和一个中立注册表。 更新后的标准(规范)加上 EF 托管的注册表 — 这是任何清晰签名合约的人类可读描述的唯一真实来源,任何人都可以复制并自行托管。
  2. ERC-8176 证明。 一个基于以太坊证明服务(EAS)的框架,允许独立审计员证明某个描述符忠实地代表了其所描述的合约。钱包自行决定信任哪些证明。
  3. ERC-8213 — 字节级后备方案。 一个由 Cyfrin 撰写的独立标准,用于即将签名的内容的简短密码学指纹,适用于 ERC-7730 无法覆盖的情况(自定义打包编码、全新合约、系统级消息)。erc8213.eth.limo 是我们的教学网站。
  4. 开发者库。 来自工作组的官方 Rust 和 TypeScript SDK,以及 Cyfrin 开源的 Python 库 clearsig — 涵盖 ERC-7730 翻译、ERC-8176 描述符哈希、ERC-8213 摘要以及 Safe 特定签名。

为什么这很重要

2025 年 2 月,Bybit 的以太坊冷钱包被盗约 15 亿美元 — 当时是有记录以来最大的加密货币盗窃案。攻击者没有破解任何密码学。他们没有绕过任何签名。多位持有硬件钱包的授权签名者批准了转移资金的交易。他们只是没有意识到自己批准了什么。

五个月前,Radiant Capital 在一场结构相同的事件中损失了约 5000 万美元:硬件钱包签名者在前端声称是常规多签操作时点击了“批准”,而他们的设备实际上授权了一个将协议逻辑交给攻击者的 delegatecall。最近,Drift Protocol 也加入了同一名单。

不同的协议。不同的时间线。相同的根本原因:人们授权了他们实际上无法读取的交易。

这种模式有一个名字:盲签 — 批准你无法验证其内容的交易,相信展示给你看的信息没有撒谎。硬件钱包本应是答案;但没有描述符,它们退回到十六进制,问题只是在更可信的屏幕上持续存在。

工作组的口号是对目标最简洁的总结:所见即所签(WYSIWYS)。在它成为默认状态、盲签成为例外而非常态之前,最后一道防线 — 审查交易的人 — 并没有发挥作用。

硬件钱包实际显示的内容

当你从硬件钱包授权交易时,设备会收到一个十六进制字符串 — 即调用数据 — 并要求你确认。在最坏的情况下,你只会看到这个:

0x6a76120200000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084617ba037000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000f42400000000000000000000000009467919138e36f0252886519f34a0f8016ddb3a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

读取它需要你:

  1. 解析四个字节的函数选择器
  2. 从合约的 ABI 中查找函数名称
  3. 根据 ABI 类型解码每个参数
  4. 解析引用的代币、地址和 ENS 名称
  5. 根据合约状态推理该调用实际会做什么

一个熟练的工程师在拥有工具和足够时间的情况下,在工作站上可以完成所有这些操作。但一个多签签名者在时间压力下,面对三行 OLED 显示屏,是无法做到的。

行业的第一反应是停止向人类显示十六进制,而是显示“发送 100 USDC 给 vitalik.eth”。但让这个版本真正安全 — 而不仅仅是更友好 — 比看起来要困难得多。

为什么仅解码 ABI 是不够的

你可能会认为 ABI 解决了问题。有了 ABI,你可以将上面的字节解码为 execTransaction(0x87870Bca..., 0, 0x617ba037..., 0, ...) 并显示每个参数。两个原因说明这仍然不够。

函数名会撒谎。 ABI 告诉你一个函数叫做 transfer。它没有告诉你 transfer 实际做什么。Solidity 允许开发者随意命名函数。没有什么能阻止一个合约将提现函数命名为 deposit,将恶意升级函数命名为 pause,或将资金提取例程命名为 claimRewards。如果你的钱包信任函数名来推导用户意图,任何部署合约的人都可以为你的钱包选择任何意图来显示。

参数需要上下文才有意义。 一个 uint256 amount 只是一个数字。Wei?6 位小数的 Micro-USDC?时间戳?以秒为单位的持续时间?基点费用?如果没有嵌入特定于协议的知识,“金额: 1000000”实际上并不是人类可读的 — 它只是不太令人警觉的十六进制版本。ABI 给你类型,而不是语义。

解码 ABI 给你一个更易读的十六进制版本。它并没有给你一个真实的版本。这种区别正是导致人们被盗的原因。

关于为什么这很难,Patrick 早些时候录制了一个解释视频:硬件钱包清晰签名

ERC-7730:描述符而非原始 ABI

ERC-7730 — 由 Ledger 起源并成熟为多供应商标准 — 解决了上述两个问题。它定义了一个 JSON 格式(描述符),将合约的函数映射到人类可读的意图和字段渲染指令。一个 USDC 描述符的 transfer 条目:

"transfer(address to,uint256 value)": {
  "intent": "Send",
  "fields": [\
    { "path": "to",    "label": "To",     "format": "addressName" },\
    { "path": "value", "label": "Amount", "format": "tokenAmount" }\
  ]
}

拥有此描述符的钱包知道:当你调用 USDC 的 transfer 时,显示“发送 {金额} 给 {接收者}”,用六位小数和 USDC 代码格式化金额,如果可用则解析接收者的 ENS 名称。

描述符由协议团队策划,由第三方审计员审查,并收集在由以太坊基金会托管的中立注册表中。钱包从注册表中拉取数据,并决定信任哪些证明。函数名和参数上下文问题得到了解决。

展示 clearsig translate

Cyfrin 的第一个贡献是 clearsig — 一个开源的 Python CLI 和库,实现了 ERC-7730 翻译、ERC-8176 描述符哈希、ERC-8213 摘要和 Safe 特定哈希。它补充了今天发布中官方 TypeScript 和 Rust 库的功能。

感受清晰签名带来的好处的最直接方法是运行一个真实的交易。这里是一个 Safe 的 execTransaction,包装了一个 Aave v3 的 1 USDC supply — 与 Bybit 攻击相同的嵌套结构。

没有清晰签名时,硬件钱包看到的是:

0x6a76120200000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084617ba037000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000f42400000000000000000000000009467919138e36f0252886519f34a0f8016ddb3a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

同样的字节,通过 ERC-7730 解码后:

clearsig translate \
  0x6a76120200000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084617ba037000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000f42400000000000000000000000009467919138e36f0252886519f34a0f8016ddb3a30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \
  --to 0x41675C099F32341bf84BFc5382aF534df5C7461a \
  --chain-id 1 \
  --from-address 0x9467919138E36f0252886519f34a0f8016dDb3a3
Intent: sign multisig operation (Safe{Wallet})
Function: execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)

  Operation type: Call
  From Safe: 0x41675C099F32341bf84BFc5382aF534df5C7461a
  Execution signer: 0x9467919138E36f0252886519f34a0f8016dDb3a3
  Transaction: Supply (Aave DAO)
  -> supply(address,uint256,address,uint16)
  Amount to supply: 1000000
  Collateral recipient: 0x9467919138e36f0252886519f34a0f8016ddb3a3
  Referral Code: 0
  Gas amount: 0
  Gas price: 0
  Gas receiver: 0x0000000000000000000000000000000000000000
  Safe Tx Gas: 0
  Signatures: 0x

外层的 execTransaction 被识别为 Safe 的多签操作;内部调用数据被识别为 Aave 的 supply,金额和接收者按名称提取出来。查看第二个版本的签名者可以判断他们在批准什么。查看第一个版本的签名者无法做到。

clearsig translate 离线运行,使用注册表的本地副本,因此签名者 — 以及审计员 — 可以在批准之前在隔离设备上进行验证。使用你偏好的 Python 工具安装:

uv tool install clearsig          # or pipx / pip
clearsig translate <calldata> --to <address> --chain-id <N>

第一次运行会自动下载 ERC-7730 注册表。使用 ERC7730_REGISTRY_PATH=/path/to/registry 指向本地检出 — 例如正在审查的 PR 分支。

当 ERC-7730 无法覆盖时:ERC-8213

描述符只存在于有人为其编写了描述符的合约。对于其他所有情况 — 全新合约、自定义打包编码(Safe MultiSend、Uniswap Universal Router)、zkSync L1 ↔ L2 系统消息 — 没有描述符可以渲染。其中一些永远不会有,因为编码不符合 ERC-7730 所假设的选择器加 ABI 模型。

ERC-8213,由 Cyfrin 撰写,就是为这些情况设计的。它定义了即将签名的内容的短、可重复的加密指纹。最简单的是调用数据摘要:

keccak256(uint256(len(calldata)) || calldata)

将命中合约的确切字节的长度前缀哈希。用例是跨设备验证:在硬件钱包上签名之前,签名者在隔离机器上计算相同的摘要 — 一台干净的笔记本电脑、一部离线手机、另一个硬件钱包。如果钱包即将签名的摘要与独立计算的摘要匹配,则字节是正确的。如果不匹配,则前端和设备之间的某些内容被替换了 — 正是导致 Bybit 和 Radiant 被盗的那类攻击。

ERC-8213 涵盖调用数据摘要、EIP-712 域/消息/最终哈希以及 Safe 特定签名哈希。它不试图使数据人类可读 — 这是 ERC-7730 的角色。它使数据可验证,这是一个较弱但始终适用的保证。

我们建立了 erc8213.eth.limo 作为在硬件钱包上使用这些摘要的教学网站 — 它还跟踪哪些钱包已经实现了该标准。第一个是 Keycard Shell,它在签名期间显示调用数据摘要以及 ABI 解码视图,因此注重安全的签名者可以通过单个哈希进行验证,而不是翻页查看十六进制。在 ERC-8213 正式化之前,关于 Safe 钱包相同模式的较旧教程在 hardware-wallet-multi-sig-signature-verification-how

仍然存在的问题

仍然存在两个实际限制,我们不想过度宣传今天发布的内容。

描述符不是即时的。 如果某个合约尚未在注册表中,就没有人类可读的渲染 — 你会回到 ABI 解码或十六进制。要包含进去需要提交 PR、审计员审查和生态系统的支持。ERC-8213 是该窗口(以及从未符合 ERC-7730 模型的合约)的后备方案,但它不能替代描述符的覆盖范围。

气隙钱包需要传输方案。 将硬件钱包气隙隔离 — 保持其与主机物理断开连接 — 是可用的最强安全姿态之一,但这使得拉取大型、频繁更新的注册表变得困难。工作组正在构建一个有线协议来解决这个问题;它尚未上线。在此之前,气隙设备上的描述符支持将落后于在线设备。

clearsig 完整说明

clearsig 将上述所有内容打包到一个 CLI 和 Python 库中:

## 这个调用数据是什么意思?(ERC-7730 翻译)
clearsig translate <calldata> --to <address> --chain-id 1

## 我的硬件钱包在签名前会显示什么摘要?(ERC-8213)
clearsig calldata-digest <calldata>

## EIP-712 类型化数据 — 域、消息和最终哈希
clearsig eip712 message.json

## Safe 交易哈希(离线) — 与 safe-hash-rs 逐字节匹配
clearsig safe-hash --chain-id 1 --safe-address 0x... --safe-version 1.4.1 ...

## Safe 链下消息(例如 OpenSea 登录)
clearsig safe-msg --chain-id 1 --safe-address 0x... --message-file msg.txt

## 对 ERC-7730 描述符进行哈希,用于 ERC-8176 证明
clearsig descriptor-hash registry/<project>/<descriptor>.json

## 从 Sourcify 为新合约引导起始描述符
clearsig generate --chain-id 1 --to 0x... --owner USDC

## 根据签名编码和解码调用数据(离线)
clearsig calldata "approve(address,uint256)" 0x05C54380408aB9c31157B7563138F798f7826aA0 1
clearsig calldata-decode "approve(address,uint256)" 0x095ea7b3...

## 函数选择器原语
clearsig sig "approve(address,uint256)"     # → 0x095ea7b3
clearsig keccak "approve(address,uint256)"  # 完整 keccak256
clearsig 4byte 0x095ea7b3                   # 通过 4byte.directory 反向查找

除了 4byte 之外的所有命令都离线运行,使用 ERC-7730 注册表的本地副本,因此签名者可以在气隙机器上验证。哈希代码与 viem(用于 EIP-712)和 safe-hash-rs(用于 Safe 哈希)逐字节交叉检查,因此 clearsig 生成的摘要是生态系统其他部分认可的摘要。clearsig generate 使用 Sourcify — 自动遍历代理到实现 — 从已验证的 ABI 引导描述符。

完整的功能,包括 Safe 多签、Aave、zkSync 和 Universal Router 边缘情况的实例,在 clearsig README 中。

Cyfrin 的承诺

清晰签名是未来几年最值得投入安全努力的领域之一。1.5 亿美元的黑客事件与毫无影响之间的差距,往往在于签名者能否读取面前的字节。Cyfrin 在这场斗争中的定位是深思熟虑的:我们不推出硬件钱包,我们对任何特定钱包的成功没有经济利益。这正是我们作为描述符审计员的有用之处 — 钱包和协议可以证明我们的审查,而无需选择立场。具体来说,Cyfrin 承诺:

  • 审计 ERC-7730 描述符。 描述符本身就是一种安全工件 — 错误的描述符可以使恶意交易看起来无害。我们将审查提交到注册表的描述符,并通过 ERC-8176(在 EAS 上)证明我们认可的描述符。注册表中的审计员说明 明确了审计员必须验证的内容。
  • walletbeat 做贡献。 这是客观跟踪钱包(软件和硬件)保护用户能力的工具。清晰签名应该出现在成绩单上。
  • 维护 clearsig、ERC-8213 和更广泛的清晰签名工具包。 除了 clearsig,我们还维护 safe-hash-rs(离线 Safe 交易哈希)、chain-tools(调用数据解码和其他签名工具)以及用于 MetaMask 的 Wise Signer Snap — 后者即将支持 ERC-8213。全部采用 MIT 许可;索引位于 docs.cyfrin.io
  • 继续标准工作。 清晰签名尚未完成 — 关于描述符生命周期、证明发现、用于气隙设备的有线协议以及描述符发布后合约发生变异时该怎么做等开放问题。我们将继续与工作组在这些问题上进行迭代。

致谢

如果没有生态系统多年的工作,此次发布就不会实现。具体来说:

  • Ledger 起源于 ERC-7730 并引导了第一个注册表、早期工具和教育工作。今天发布的版本直接建立在那项工作之上。
  • Trezor 在交易解析和设备端用户体验方面的持续投入,塑造了行业对这个问题的思考方式。
  • KeystoneGridPlus 成为首批(据我们所知)直接在签名设备上进行 ABI 解码的硬件钱包,而不是依赖配套应用。设备本身(而非其主机)应该显示解码后的交易,这一原则正是清晰签名有意义的基础。
  • 全体工作组 — Ledger、Trezor、MetaMask、WalletConnect、Keycard、ZKnox、Blockaid、Fireblocks、Zama、Sourcify、Argot 以及以太坊基金会的万亿美元安全倡议 — 使这成为一项多供应商、多团队的努力,而非单一供应商的推动。

接下来做什么

  • 协议团队:为你的合约发布描述符。如果你希望用户信任他们签署的内容,就给他们提供可读的内容。clearsig generate 从已验证的 ABI 生成起点;手动完善意图和标签。
  • 审计员:进行证明。信任图只有在审查者真正参与时才能起作用。审计流程在此处有文档说明。
  • 钱包开发者:集成今天发布的库。让盲签成为例外而非默认。
  • 签名者:停止签署你无法读取的内容。当风险较高时,使用第二台设备进行验证 — clearsig translateclearsig calldata-digest 正是为此设计的。

资源

  • 原文链接: cyfrin.io/blog/blind-sig...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论