D
开发工具箱

TOTP 详解:两步验证背后的时间密码

安全工具 2026年6月17日 约 1 分钟阅读

两步验证为什么需要 TOTP?

密码泄露太常见了。哪怕你设了强密码,一旦网站被拖库、或你在钓鱼网站输入了密码,账号就裸奔。两步验证(2FA)的思路是:除了密码这”你知道的东西”,再加一层”你拥有的东西”——通常是手机上实时变化的一串 6 位数。

这串每 30 秒变一次的数字就是 TOTP(Time-based One-Time Password,基于时间的一次性密码)。它最神奇的地方在于:你的手机和服务器从不需要联网同步,却能算出完全相同的 6 位数。没有网络、没有短信、完全离线,这怎么做到的?

答案就一句话:双方共享同一个密钥,加上当前时间,用同样的算法各自算一遍——结果自然一样。

从 HOTP 说起:计数器版的一次性密码

TOTP 是 HOTP 的改进版,得先理解 HOTP。HOTP(RFC 4226)的核心是:

  1. 绑定阶段:服务器给用户发一个共享密钥 K(一段随机字节,通常 Base32 编码,就是你扫码时存进验证器 App 的那个 secret)
  2. 生成阶段:双方各维护一个计数器 C。每次生成验证码,用 HMAC 算 HMAC-SHA1(K, C),再从哈希里截取 6 位数字作为本次 OTP
  3. 验证阶段:用户把 6 位数给服务器,服务器用自己当前的计数器算一遍,匹配则通过,并把计数器 +1

因为 HMAC 是确定性的——同样的密钥 + 同样的计数器,永远算出同样的结果——所以双方各自算,结果必然一致。整个过程中密钥从不传输,只传输一次性的 6 位数,截获了也没用(用完即废)。

HOTP 的问题是依赖计数器同步:你按了 5 次生成码但没登录,计数器就比服务器超前 5,得重新同步。手机 App 来回同步计数器很麻烦。

TOTP:用时间代替计数器

TOTP(RFC 6238)做了一个聪明的改动:把计数器换成”当前时间除以 30 秒”

C = floor(当前 Unix 时间戳 / 30)

这样双方都不用维护计数器状态——只要时钟大致准确(30 秒一个窗口,容错很宽),同一时刻算出的 C 必然相同。剩下的步骤和 HOTP 完全一样:HMAC-SHA1(K, C) → 截取 6 位数字。

这就是为什么手机离线也能算出和服务器一样的码:密钥相同(扫码时绑定)+ 时间相同(都看时钟)+ 算法相同(标准 HMAC)。三方一致,结果一致。TOTP 本质就是”用时间当计数器的 HOTP”。

30 秒窗口的取舍

为什么是 30 秒,不是 5 秒或 5 分钟?

  • 太短(如 5 秒):用户手慢输不完就过期,体验差
  • 太长(如 5 分钟):一个验证码有效时间太长,被截获后可重复使用的窗口大,安全性降
  • 30 秒:经验上的平衡点,足够输入,又不会让单个码暴露太久

服务器验证时通常会允许前后一个窗口的容错(即当前、上一个、下一个 30 秒窗口都接受),应对轻微的时钟偏差和用户手速。但不会允许太多窗口,否则就削弱了”一次性”。

二维码里到底存了什么?

绑定 TOTP 时扫的那个二维码(otpauth URI),内容长这样:

otpauth://totp/网站名:用户名?secret=JBSWY3DPEHPK3PXP&issuer=网站名&period=30&digits=6

关键字段:

  • secret:共享密钥,Base32 编码。这是整个 2FA 的核心,泄露它等于 2FA 失效
  • issuer / label:显示用的网站名和账号名
  • period:时间窗口,默认 30 秒
  • digits:验证码位数,默认 6 位(也有 8 位的)

扫描后这些信息(尤其是 secret)被存进验证器 App,之后完全离线工作。所以绑定时的二维码/secret 务必备份——换手机时如果没备份 secret,就再也登不进账号了(很多服务因此提供”恢复码”,务必保存)。

安全性分析

TOTP 防的是什么?主要防密码泄露后的远程登录——攻击者就算拿到了密码,没有你手机上的实时验证码也进不去。

但 TOTP 不是万能:

  1. 不防钓鱼:攻击者搞个假登录页,骗你同时输入密码和当前 TOTP,他可以拿这俩在 30 秒内中继登录真站(中间人钓鱼,FIDO2/WebAuthn 才能防这招)
  2. secret 泄露即失效:如果 secret 被偷(比如 App 数据被恶意软件读取),攻击者能自己算验证码
  3. 不防暴力:6 位数字只有 100 万种,如果服务器不限制尝试次数,理论上能暴力——所以服务端必须限流(通常 5 次失败锁定)
  4. 同步问题:手机时钟偏移太大可能导致算出的码不在容错窗口内,需要重新校时

TOTP vs HOTP vs 短信验证码

方式同步依赖离线可用安全性体验
短信验证码依赖运营商网络较低(SIM 劫持、短信嗅探)
HOTP计数器同步需手动同步
TOTP时钟同步
FIDO2/WebAuthn否(需硬件)最高(防钓鱼)最好

短信验证码看似方便,但安全性最差——SIM 劫持攻击能让攻击者接管你的手机号收验证码。TOTP 是当前性价比最高的 2FA 方案,FIDO2 是未来的方向。

小结

TOTP 的精髓是用”共享密钥 + 当前时间 + HMAC”实现无需联网的双方一致性验证。理解了它是 HOTP 的时间版、底层是 [[hmac]],你就明白了所有 OTP 类工具的原理。它的核心价值是给账号加一层独立于密码的防护,但记得:绑定的 secret 务必备份,恢复码务必保存——丢了这两样,2FA 反而会把你锁在自己的账号外。