一句话版本
签名是加密货币世界里唯一的"授权"动作:私钥一签,链上就认。所以签名前最重要的问题是:我到底在签什么? "盲签"就是签一串自己看不懂的数据,等于在空白支票上签名。今天占比最高的盗币手法 Permit / Permit2 签名钓鱼,就是让用户以为自己在"登录"或"领空投",实际签下的是"允许某人转走我的代币"。防御的核心原则叫所见即所签(What You See Is What You Sign):钱包必须能把签名内容完整解码、用人话展示,解码不了就不签。
全文分三层:
- 通俗理解:空白支票
- 实际用处:Permit 钓鱼、Bybit 事件、硬件钱包的"清晰签名"
- 原理与工程要点:
eth_sign、personal_sign、EIP-712、Permit 的结构
第一层:通俗理解
1.1 空白支票
有人递给你一张纸,上面是一串乱码:"0x8f3a...e21c,请签名确认。"你签了。
后来才知道,这串乱码翻译过来是:"本人同意,把我账户里所有 USDC 的转出权交给 0xBad...。"
这就是盲签。签名算法本身毫无问题,问题是你不知道自己签了什么。
1.2 链下签名为什么更危险
很多人以为"只要不发交易、不花 gas,就没有风险"。但有一类签名不上链、不花钱,却能被别人拿去上链执行:
- 你签一条 Permit 消息,网站显示"签名成功,正在为你领取空投";
- 攻击者拿着你的签名,自己发一笔交易,把你的代币授权给他,再转走。
整个过程你的钱包里没有出现过任何一笔交易请求,只有一次"签名"。
第二层:实际用处
- Permit / Permit2 钓鱼:链上安全公司的年度报告显示,签名类钓鱼已经是加密货币用户损失的最大来源之一,单个受害者一次损失上千万美元的案例屡见不鲜。常见话术:领空投、验证钱包、免费铸造、"签名登录"。
- Bybit(2025):签名人在硬件钱包上看到的是无法直接读懂的交易数据,只能信任网页的显示,而网页被篡改了(见《Bybit事件与前端完整性》)。事后,行业里对"硬件钱包必须清晰显示多签交易内容"的呼声空前高涨。
- 硬件钱包的"清晰签名"(clear signing):Ledger、Trezor 等厂商正在推进在设备屏幕上直接显示解码后的交易,例如"授权 Uniswap 使用 1000 USDC,有效期到某日",而不是一串十六进制。
- 钱包的安全提示:MetaMask、Rabby 等会对 Permit 类签名显示醒目警告,并解析出 spender(被授权方)和额度。
Caloogy Wallet 也采用了"只签可完整解码的内容"的原则,并禁用了危险的签名方法。
第三层:原理与工程要点
3.1 以太坊的几种签名方法
| 方法 | 签的是什么 | 风险 |
|---|---|---|
eth_sign |
任意 32 字节哈希 | 最高:这个哈希可能就是一笔交易的哈希,用户完全无法辨认。主流钱包已默认禁用 |
personal_sign |
加了固定前缀 "\x19Ethereum Signed Message:\n" + 长度 的消息 |
前缀保证它不可能是交易。签可读文本时安全;签裸十六进制时仍是盲签 |
eth_signTypedData_v4(EIP-712) |
结构化数据,带 domain(应用名、链 ID、合约地址) | 钱包可以解析展示,但用户必须真的读懂 |
eth_sendTransaction |
一笔交易 | 钱包会展示 to、value、data,但 data 需要解码 |
3.2 EIP-712 的结构
{
"domain": { "name": "USD Coin", "version": "2", "chainId": 1,
"verifyingContract": "0xA0b8...eB48" },
"primaryType": "Permit",
"message": {
"owner": "0x你的地址",
"spender": "0x攻击者地址",
"value": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": 0,
"deadline": 1893456000
}
}
翻译成人话:"我允许 0x攻击者地址,从现在到 2030 年 1 月 1 日,花掉我所有的 USDC。"
其中 value 那个天文数字是 ,即"无限额"(见《无限额授权》)。签名之后,任何人都可以把这份签名提交给 USDC 合约的 permit 函数,链上就会记录这次授权;接着 spender 调用 transferFrom 就能把钱转走。
3.3 Permit2
Uniswap 推出的 Permit2 是一个通用授权合约:用户先对 Permit2 做一次(通常是无限额的)链上授权,以后各个应用都只需要用户签名就能动用代币。体验更好,但也意味着:一次被骗的签名,就能动用你授权给 Permit2 的全部代币。
3.4 "所见即所签"的工程原则
- 不支持
eth_sign,不对裸十六进制使用personal_sign; - 只签能完整解码的内容:交易的 calldata 要解析出函数名和参数,EIP-712 要识别出 spender、额度、期限;
- 解码不了就拒绝,而不是"显示原始数据让用户自己判断"(见《Fail-closed》);
- 对授权类签名显示最醒目的警告:"这等于把你的资产交给 X";
- 签名请求必须由用户的点击直接触发,页面加载时绝不自动弹出签名;
- 对多签钱包,签名人要能独立于网页(在硬件钱包屏幕上、或用另一套工具)解码交易,例如检查
operation字段是否是危险的delegatecall。
总结
| 层次 | 要点 |
|---|---|
| 直觉 | 盲签 = 在空白支票上签字 |
| 现实 | 链下签名不花 gas,却能被拿去上链转走资产 |
| 技术 | 禁用 eth_sign;EIP-712 可解析,但仍要读懂 spender 和额度 |
| 原则 | 所见即所签:解码不了就不签;硬件钱包清晰显示 |