eth_sign 签名算法的历史

背景

一般刚入行 web3 的用户都会接触到 metamask,metamsk 里有一个 eth_sign 的签名方法很特别,因为用这种方法签名时会有很醒目的红字提示:

本文(尽我所能地)简述下这个“危险”的签名算法的发展历史

历史

eth rpc 文档 里找到 eth_sign 的说明:

这个说明跟 metamask 对于 eth_sign 的定义是不一样的,metamask 是单纯的直接对 message 的签名,但节点的 rpc 接口却是加了 一段通用前缀 后拼接上 message 再进行签名

好奇这样截然不同的签名逻辑不会引起混乱吗?于是开始继续探索,搜索了一些 issue 和资料后,总结了原因如下:

  1. 在 ETH 的 Homestead 发布之前(2016-02-29) ,节点 rpc 接口 eth_sign 一直都是不带前缀的,会直接对原字符串进行签名
  2. 后来考虑到这样的 eth_sign 比较危险(恶意 dapp 可以提前组好一笔转账交易,计算出最后的 digest ,最后诱导用户使用 eth_sign 签名),在 Homestead 发布后将节点里的 rpc 接口 eth_sign 的签名逻辑修改成:在原字符串之前添加一个 固定前缀,然后再对其进行签名

关于这个 固定前缀 的解释可以参考 eip191

影响

这样的暴力更新破坏了向后兼容(因为没有新增接口,也没有删除接口,而是直接简单粗暴地修改了原有接口的执行逻辑),所以一些其他周边产品就需要有对应的更改和逻辑适配。

后端

后端 eth 库 go-ethereum 在 2016-04-26 的这个 PR 做了如下逻辑:

  1. 修正 eth_sign 的逻辑以保持跟 rpc 接口一致
  2. 新增 personal_sign 接口(其实跟 eth_sign 是一模一样的行为)
  3. 新增 personal_recover 接口(新增了 sign,自然也需要一个对应的 recover)

前端

  1. 前端库 ethers.js 在某个 issue 也吐槽/讨论了这个混乱的变更
  2. 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 接口逻辑