TOTP 生成器
根据 base32 密钥生成并校验基于时间的一次性密码(TOTP),兼容 Google 身份验证器与 RFC 6238。
一次性密码,RFC 6238。 根据 base32 密钥生成当前 TOTP,并校验你收到的验证码。计数器由当前时间推导,因此每 30 或 60 秒刷新一次。全部在浏览器内完成。
根据 base32 密钥生成并校验基于时间的一次性密码(TOTP),兼容 Google 身份验证器与 RFC 6238。
一次性密码,RFC 6238。 根据 base32 密钥生成当前 TOTP,并校验你收到的验证码。计数器由当前时间推导,因此每 30 或 60 秒刷新一次。全部在浏览器内完成。
TOTP 由 RFC 6238 定义,本质上是 HOTP 之上的一层薄封装。双方持有同一个密钥,通常在开通时以二维码形式交付一次,并保存在验证器应用中。生成验证码时,两侧各自取当前 Unix 时间,除以步长(默认 30 秒)得到计数器,用密钥对该计数器做 HMAC-SHA1,再把结果截断成所需位数。
由于计数器来自时钟而非某条消息,开通之后两方之间无需再传输任何数据。服务端不必下发挑战值,应用也不需要网络连接——这正是验证器应用在飞行模式下依然可用的原因。
HMAC 输出 20 字节,远多于一个 6 位验证码所需。动态截断的做法是:取最后一个字节的低四位作为偏移量,从该位置读取 4 个字节,屏蔽最高位以避免符号问题,再对 10^位数 取模。使用可变偏移而非固定偏移,意味着攻击者无法把分析集中在摘要中某个已知片段上。
6 位几乎是通用默认值。多数应用也支持 8 位,能多提供约两位十进制的抗猜测能力,但这远不如限流重要——6 位验证码单次猜中的概率是百万分之一,真正的防线是连续失败几次后锁定。
设备时钟会漂移。服务端通常除当前窗口外,还接受前一个和后一个窗口的验证码,从而提供约 ±30 秒的容差。把窗口放宽到一两分钟以上,攻击面就会明显增大,而且这通常说明该修的是设备时钟。
部署时有两点值得记牢。一是验证码在整个窗口内都有效,因此被截获的验证码可以在该窗口内重放,除非服务端把用过的计数器标记为已消费。二是密钥是对称的:任何拿到服务端副本的人都能永久生成有效验证码,所以它需要与密码数据库同等级别的保护——静态加密、绝不写日志、绝不进 git 仓库。