六位数验证码为什么会自己变化?TOTP 的时间密码
TL;DR
解释身份验证器如何利用共享秘密和时间窗口生成一次性验证码,以及它与短信验证和 Passkey 的区别。
身份验证器里的验证码不是服务器不断发来的短信,而是手机和服务器根据共享秘密与当前时间独立计算出的短期密码。本文解释 TOTP 的工作方式和换机注意事项。

身份验证器里的六位数验证码通常每隔几十秒就会变化。它看起来像一串随机数字,实际上并不是服务器临时发来的短信,而是手机和服务器根据同一份秘密信息、同一个时间窗口,各自计算出相同结果。这类机制叫 TOTP:基于时间的一次性密码。
手机和服务器并不是一直互相发消息
绑定身份验证器时,服务通常会给手机一份共享秘密,常见形式是二维码或一串字符。之后,手机根据当前 Unix 时间把时间切成固定长度的窗口,再用共享秘密计算一个 HMAC 值,最后截取其中一部分变成六位或八位数字。服务器用同样的秘密和时间计算,如果结果一致,就接受这次验证。
为什么时间不准也可能成功
现实设备的时钟不一定完全一致,服务器通常会允许当前时间窗口前后的一小段偏差。例如,手机显示的代码刚刚跨过 30 秒边界,服务器可能仍会检查相邻窗口,避免用户因为网络延迟或系统时钟轻微漂移而频繁失败。但允许的窗口不能无限扩大,否则旧代码的有效时间变长,攻击者尝试的机会也会增加。
RFC 6238 把时间步长、共享秘密、哈希算法和校时要求写成了可互操作的规范。默认时间步长常见为 30 秒,但具体服务也可以使用不同设置。所谓“代码过期”,本质上是当前时间已经进入了另一个计算窗口。
一次性到底体现在哪里
同一个时间窗口内,手机可能显示相同的数字,但服务器通常不应让成功使用过的代码被重复接受。一次性更多体现为服务端的验证策略,而不是数字在屏幕上每秒都变化。
TOTP 也不是抗钓鱼认证。仿冒网站可以在你输入验证码后,立刻把它转发给真实网站,只要代码还在有效窗口内,攻击者就可能完成登录。因此,身份验证器比短信更稳妥,却仍然不如和域名绑定的 Passkey 或安全密钥。
换手机时要注意什么
验证器里的共享秘密如果没有迁移或备份,换手机后可能无法生成正确代码。设置 MFA 时应同时保存官方提供的恢复代码,并确认账号还有至少一种可用的恢复方式。恢复代码本身相当于高权限钥匙,不应截图后长期放在公开相册或聊天记录里。
六位数验证码并不神秘:它是一个让手机和服务器在没有持续通信的情况下,对“同一时间、同一秘密”达成短暂共识的算法。



