域名不一致的 EIP-712 签名,一概不签。 这不是"较真",而是 EIP-712 的安全机制——域名(Domain)里的 chainId 和 verifyingContract 字段就是用来防止签名被跨链、跨合约重放的。不一致说明这笔签名可能被用在别处。
1. 先搞清楚 EIP-712 的"域名"是干什么的
EIP-712 是为结构化数据设计的签名标准,你钱包里看到的"请签名"弹窗,本质上是让你签一段"类型化数据"(Typed Data)。
这段数据里有个核心部分叫 域名分隔器(Domain Separator),通常包含四个关键字段:
name:应用的名称version:版本号chainId:链 ID(如以太坊主网是 1)verifyingContract:验证签名的合约地址
这几个字段组合起来,唯一标识"这笔签名到底是在什么场景下用的"。域名不一致,意味着这个签名可能不是为当前这个 DApp 准备的。
2. 为什么说"域名不一致"是严重的警告信号
如果域名里的 chainId 或 verifyingContract 和你当前连接的网站对不上,这通常意味着签名请求来自一个恶意构造的页面。
① 缺少 chainId:签名可以在别的链上重放
OWASP 的智能合约安全标准明确指出,如果 EIP-712 域名里没有 chainId 和 verifyingContract,签名可能被跨合约、跨链重放,导致攻击者用你在一条链上的签名去另一条链上授权操作。
② 缺少 verifyingContract:签名可以在别的合约地址上使用
GitHub 上有真实的审计案例:由于 verifyingContract 缺失,同一个签名在多个合约地址间都能生效,攻击者可以直接用你在一处签的名去调用另一处的函数。另一个案例中,缺少 version 字段导致两个不同版本的合约域名结构相同,签名在版本间可互相复用。
③ chainId 写死为固定值:链分叉后签名可能失效或被重放
如果域名里的 chainId 是写死的而非动态读取 block.chainid,链升级或分叉后,原有签名可能全部失效;如果攻击者利用分叉链环境重新构建,也可能造成重放。
3. 收到域名不一致的签名请求,怎么做
步骤1:拒绝签名,不要点"确认"
做什么:直接关闭签名弹窗,不要尝试修改或确认。
怎么做:
如果钱包弹窗显示"Sign typed data"且附带一串看起来像域名结构的数据,先看
verifyingContract是不是当前 DApp 的合约地址。如果显示的是
0x000...或一个你从未交互过的地址,拒绝。部分钱包(如 Phantom、Rabby)会直接高亮显示域名信息,重点看
chainId和verifyingContract是否匹配当前环境。
步骤2:用工具解码 EIP-712 请求,查看完整域名
做什么:在签名前,用工具解析这笔签名请求的完整内容。
怎么做:
使用 ShieldForge 等浏览器扩展,它可以在你签名前自动解码 EIP-712 类型化数据,展示
domain、message和primaryType,并对"无限授权"值发出警告。也可以使用
viem的verifyTypedData函数离线验证域名和消息是否匹配。
做到什么程度算完成:你确认了这笔签名请求中的域名字段(
name、version、chainId、verifyingContract)是否全部指向你当前交互的 DApp。
步骤3:仅当域名完全匹配当前 DApp 时,才考虑签名
做什么:确认以下三个条件全部满足,再考虑签名:
name和version是当前 DApp 的名称和版本chainId与当前连接的链完全一致(主网不能是 1,测试网是 11155111 等)verifyingContract是当前页面上能查到的合约地址(可以去区块浏览器上核实)
做到什么程度算完成:所有字段逐一比对通过,没有"看起来差不多"的模糊空间。
前置条件:钱包已连接到一个 DApp,且 DApp 请求你签署一笔 EIP-712 签名。
常见失败原因:用户看到"Sign typed data"字样,以为只是"登录",没看域名就直接确认。近年大量资产被盗事件,根源就是盲签(Blind Signing)——即在不清楚签名内容的情况下点击确认。
风险提醒:硬件钱包或冷钱包对 EIP-712 签名没有额外保护——因为这类签名本身就是"离线"授权的设计,不需要 Gas,不需要上链确认。一旦你签了,攻击者可以立即在别的链上或别的合约上使用这笔签名,而不需要你再次确认。
做完以上检查,怎么确认自己安全了?
收到 EIP-712 签名请求时,展开钱包里的"Domain"详情,确认 chainId 是你当前连接的链号、verifyingContract 是你交互的合约地址。如果其中任何一个和预期不符,点"拒绝"。只有完全匹配,才能继续操作。如果对某个请求不确定,用 ShieldForge 等工具解码后再决定。



