Caloogy 文章
English

签名登录与防重放:nonce、域名、过期时间

日期
2026 年 7 月 23 日
系列
Web 安全
阅读
3 分钟
主题
SiweEip 4361Replay attackNonce

一句话版本

"用钱包签一条消息来证明地址是你的"(Sign-In with Ethereum,EIP-4361)比密码更安全,但前提是这条消息里写清楚了给谁签、什么时候签、只能用一次。 少了任何一项,攻击者都能把你的签名拿去重放:换个网站用、过一个月再用、在另一条链上用。防重放的三件套是:一次性随机数(nonce)、域名绑定、时间窗口。

全文分三层:

  1. 通俗理解:什么是重放攻击
  2. 实际用处:SIWE、跨链重放事件、API 签名
  3. 原理与工程要点:SIWE 消息逐行解读、服务端校验清单、EIP-155

第一层:通俗理解

1.1 重放攻击

你给门卫出示一张签了名的条子:"请让我进去。"门卫验了签名,放行。

问题是:如果有人在旁边复印了这张条子,明天拿来再出示一次,门卫一验,签名还是真的,于是也放行了。签名本身没被伪造,只是被重复使用了。这就是重放攻击。

1.2 怎么防

在条子上多写几样东西:

写上 效果
"今天门卫给我的暗号是 7341" 每次的暗号都不同,旧条子作废(nonce)
"给 A 公司的门卫" 拿去 B 公司没用(域名绑定)
"下午 3:00 到 3:10 有效" 过期作废(时间窗口)

第二层:实际用处

Caloogy Wallet 也采用了 SIWE 绑定地址,并要求签名只能使用一次。


第三层:原理与工程要点

3.1 一条 SIWE 消息长什么样

example.com wants you to sign in with your Ethereum account:
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed

Bind this address to your account.

URI: https://example.com
Version: 1
Chain ID: 1
Nonce: 8f3k2QpZ7mXw
Issued At: 2026-11-05T10:00:00Z
Expiration Time: 2026-11-05T10:05:00Z
字段 防什么
第一行的域名 钓鱼站诱导你签"给 example.com 的消息":钱包会对比当前网站和消息里的域名
地址 签名必须恢复出这个地址
Chain ID 跨链重放
Nonce 同一签名被用第二次
Issued At / Expiration Time 很久以前截获的签名被拿来用

3.2 服务端校验清单

  1. nonce 必须由服务器生成并记录,绑定到当前会话,用过立即作废;
  2. 消息里的域名、URI 必须是自己的;
  3. 当前时间在 Issued At 和 Expiration Time 之间;
  4. 用 ecrecover 从签名恢复出地址,必须和消息里的地址一致;
  5. 智能合约钱包(如 Safe)没有私钥,要改用 EIP-1271 调用合约的 isValidSignature 验证。

第 1 条最容易做错:如果 nonce 由客户端生成,或者服务端不记录"用过的 nonce",防重放就形同虚设。

3.3 EIP-155:把链 ID 签进交易

EIP-155 之前,交易签名的内容是 (nonce, gasPrice, gasLimit, to, value, data),里面没有任何"这是哪条链"的信息。EIP-155 之后变成

Sign(RLP(nonce,gasPrice,gasLimit,to,value,data,chainId,0,0)),\mathrm{Sign}\big(\mathrm{RLP}(\text{nonce}, \text{gasPrice}, \text{gasLimit}, \text{to}, \text{value}, \text{data}, \textbf{chainId}, 0, 0)\big),

签名里的 vv 值也编码了 chainId。现在主流钱包都强制使用 EIP-155,EIP-712 的结构化签名也有自己的 domain(含 chainId 和合约地址),见《盲签与所见即所签》。

3.4 只签你看得懂的东西

签名登录安全的另一个前提,是钱包能把消息解析并展示出来。如果网站让你签一串看不懂的十六进制(eth_sign 签裸哈希),那它可能根本不是登录消息,而是一笔交易的哈希。所以正确的实现要求:登录只用 personal_sign 签可读文本,从不使用 eth_sign。


总结

层次 要点
直觉 真签名也会被复印再用,要写上"给谁、何时、仅一次"
三件套 nonce(服务器发、用完作废)、域名、时间窗口
链上 EIP-155 把 chainId 签进交易,终结跨链重放
底线 只签可读、可解析的消息