背景
一般刚入行 web3 的用户都会接触到 metamask,metamsk 里有一个
eth_sign
的签名方法很特别,因为用这种方法签名时会有很醒目的红字提示:
本文(尽我所能地)简述下这个“危险”的签名算法的发展历史
历史
在 eth
rpc 文档 里找到 eth_sign
的说明:
这个说明跟 metamask 对于
eth_sign
的定义是不一样的,metamask 是单纯的直接对 message 的签名,但节点的 rpc 接口却是加了 一段通用前缀 后拼接上 message 再进行签名
好奇这样截然不同的签名逻辑不会引起混乱吗?于是开始继续探索,搜索了一些 issue 和资料后,总结了原因如下:
- 在 ETH 的 Homestead
发布之前(2016-02-29) ,节点 rpc 接口
eth_sign
一直都是不带前缀的,会直接对原字符串进行签名 - 后来考虑到这样的
eth_sign
比较危险(恶意 dapp 可以提前组好一笔转账交易,计算出最后的 digest ,最后诱导用户使用eth_sign
签名),在 Homestead 发布后将节点里的 rpc 接口eth_sign
的签名逻辑修改成:在原字符串之前添加一个 固定前缀,然后再对其进行签名
关于这个 固定前缀 的解释可以参考 eip191
影响
这样的暴力更新破坏了向后兼容(因为没有新增接口,也没有删除接口,而是直接简单粗暴地修改了原有接口的执行逻辑),所以一些其他周边产品就需要有对应的更改和逻辑适配。
后端
后端 eth 库 go-ethereum 在 2016-04-26 的这个 PR 做了如下逻辑:
- 修正
eth_sign
的逻辑以保持跟 rpc 接口一致 - 新增
personal_sign
接口(其实跟eth_sign
是一模一样的行为) - 新增
personal_recover
接口(新增了 sign,自然也需要一个对应的 recover)
前端
- 前端库 ethers.js 在某个 issue 也吐槽/讨论了这个混乱的变更
- Metamask 的
eth_sign
依旧是 Homestead 之前的节点 rpc 逻辑,但界面会有醒目的红字提醒,在其官方的 开发者文档 里也解释了这么做的原因
硬件钱包
钱包名 | 支持程度 |
---|---|
ledger | 不支持 eth_sign (会走
personal_sign ) |
onekey | 不支持 eth_sign (会走
personal_sign ) |
imkey | 支持 eth_sign ,但在 imkey manager 环境里且只在
app.da.systems 的 eip712Hash 计算有问题 |
trezor | 支持 eth_sign ,不支持 eip712,详情见其官方库的 issue
(貌似现在已经支持了) |
上表中提到的 eth_sign
指的是不带前缀的签名方式,即
Homestead 之前的 rpc 接口逻辑