太长不看
地址投毒攻击之所以有效,是因为人们只会验证地址的前缀/后缀。本文提出了一种仅需钱包/用户界面即可实现的机制:接收方共享一个短暂的接收代码,发送方的钱包使用Keccak256(address || code)来生成动态校验和指纹。如果发送方不小心粘贴了一个被投毒的相似地址,验证就会失败,因为攻击者不知道该代码。
动机:常见的习惯中毒伎俩
实际上,很少有用户会逐个验证 40 个十六进制字符。主要的工作流程(尤其是在复制最近活动时)是:
- 检查前4-6个字符
- 检查最后4-6个字符
- 假设中间部分没问题
投毒攻击直接针对这一点:
- 攻击者生成一个与常用收件人地址具有相同可见前缀/后缀的地址
- 攻击者发送一个值为 0 的/尘埃的转账,使仿冒品出现在“最近”历史记录中。
- 用户复制了错误的条目,前缀/后缀匹配,资金被发送给了攻击者。
这主要是用户界面/人工验证方面的失误,而不是协议漏洞。
直觉:以太坊转账缺乏“二次确认”。
在许多传统的支付流程中,实际上需要确认两件事:
- 目的地标识符(账号)
- 独立的确认信号(收款人姓名/确认提示)
以太坊拥有强大的目标标识符(地址),但当用户向原始的0x…地址转账时,通常缺少第二重确认。因此,我们的目标是添加一个轻量级的第二重验证因素:
- 链下(仅限钱包)
- 便宜(无需额外的链式步骤)
- 投毒者很难预料到具体的付款金额。
背景:校验和大小写是什么,以及为什么它不足以满足要求。
钱包地址通常会显示大小写混合的“校验和”地址。其基本原理是:
- 根据地址计算哈希值
- 使用哈希值中的部分内容来确定十六进制字母
a–f的大小写。 - 如果地址发生变化,大小写规则很可能不再有效,这有助于发现拼写错误。
这里广泛使用的以太坊约定是EIP-55校验和封装。
投毒限制:此外壳是每个地址固定的,并且可公开计算,因此投毒的类似物也可以显示为“有效的校验和”形式。
建议:使校验和大小写取决于接收方提供的代码(动态指纹)
输入
addr:收件人地址(20 字节)-
code:简短的接收者代码(字符串;建议使用一次性或短期代码)
哈希
我们计算如下:
H = Keccak256(addr\_bytes || code\_utf8)
H = K e c c a k 256 ( a d d r _ b y t e s | | co d e _ u t f 8 )
其中addr_bytes是 20 字节的地址, code_utf8是接收器代码的 UTF-8 编码。使用 20 字节的地址可以确保连接边界清晰明确。
套圈规则
将地址渲染为十六进制(照常)。对于每个字符:
- 数字
0–9保持不变 - 字母
a–f根据H的连续比特位进行大写/小写转换。
(与 EIP-55 精神相同,但使用上述H)
结果:相同的底层地址现在具有特定于代码的大小写指纹。
流动
接收者(爱丽丝)
- Alice 生成一个接收代码(建议使用钱包生成的代码),例如
lamp-snow-47。 - 钱包显示地址,其大小写源自
H - Alice 与发件人共享(地址,代码) 。
发件人(鲍勃)
- 鲍勃粘贴了地址。
- 鲍勃输入接收器代码。
- 钱包重新计算并验证外壳指纹:
- 匹配→ 已验证
- 不匹配→ 警告/阻止(错误代码、错误地址或可能存在恶意代码)
其目的是让用户依靠清晰的已验证/未验证状态,而不是通过目视检查外壳。
为什么这样做可以减轻中毒风险(针对目标场景)
当用户不小心从历史记录中选择了相似的前缀/后缀时,投毒攻击就会成功。使用接收代码:
- 攻击者仍然可以伪造相似的地址,并将其添加到用户的历史记录中。
- 但攻击者无法使被污染的地址在接收方的代码下验证通过。
- 因此,“从历史记录中复制错误地址”不再是悄无声息的成功,而变成了确定性的验证失败。
期待您的反馈——特别是关于用户体验方面的权衡取舍,以及我可能忽略的威胁模型或实现中任何潜在的缺陷。提前感谢您的反馈!




