TOTP 是什么
TOTP(基于时间的一次性口令)的核心很朴素:服务端和你的验证器 App 共享一个种子密钥,双方用「当前时间步长(通常 30 秒)+ HMAC-SHA1」算出同一串 6 位数字。服务器只要比对是否相等即可。
它到底防什么
2FA 防的是密码泄露或撞库:攻击者即使拿到你的密码,没有种子密钥也生成不了下一步的动态码。但它不防实时钓鱼——中间人可以把你刚输入的动态码立刻转发到真网站。
三种 2FA 强度对比
| 方式 | 强度 | 弱点 |
|---|---|---|
| 短信验证码 | 弱 | 可被 SIM 交换、信号拦截、运营商内部人员获取 |
| TOTP 验证器 App | 中 | 不绑定域名,易被实时钓鱼转发 |
| 硬件密钥 / Passkey(WebAuthn) | 强 | 绑定域名,钓鱼无法重放;需设备支持 |
使用建议
- 优先级:硬件密钥或 Passkey 最好,其次 TOTP App;短信验证码只作为兜底;
- 保存恢复码:离线打印或密码管理器存一份,防止丢手机后锁死账号;
- 分开存放:不要把 TOTP 种子和主密码存在同一处(别让密码管理器既存密码又存动态码还同步到同一云);
- 时间校准:验证失败先确认设备时间准确,时间漂移会让动态码对不上。
种子密钥与二维码
开通 2FA 时看到的二维码是 otpauth:// 链接,其中种子用 Base32 编码。截图保存等于泄露种子,请用支持加密导出的验证器。
动手试试
接入 TOTP 的实操细节
TOTP 的标准流程并不复杂(共享密钥 + 时间片 HMAC 取模),但工程细节决定安全性:
- 密钥要求:使用至少 160 位随机字节,用 Base32 展示给用户;密钥只在绑定时展示一次,之后加密存储且不可再明文读出;
- 时间对齐:服务端应接受前后各一个时间片(共三个 30 秒窗口)以容忍客户端时钟漂移,但不能无限放宽;
- 防重放:同一个 6 位码在有效期内只能成功一次,需要记录已用过的计数器值,否则码被截获后仍可复用;
- 限速:6 位码只有一百万种组合,必须限制连续失败次数并触发锁定或冷却,否则可被在线爆破;
- 恢复码:为丢失设备的用户提供一次性恢复码,哈希存储且用后作废,并提供解绑与重新绑定路径。
常见误区
- 用短信当第二因素:短信可被劫持或补卡,安全性显著低于 TOTP;
- 把密钥放进二维码就不管了:二维码只是传输载体,密钥本身仍需加密存储;
- 认为“有 2FA 就安全”:若登录页可被实时钓鱼转发,TOTP 同样会被利用,高价值场景应升级为 WebAuthn;
- 只在前端校验:校验必须完全在服务端完成,前端只是输入与展示。
与其它第二因素的取舍
按抗钓鱼能力排序大致是:WebAuthn(硬件密钥 / 平台验证器)优于 TOTP,TOTP 优于推送确认,短信最弱。选择时同时考虑用户设备的普及度与客服成本。
客户端时间偏差怎么处理
- 接受相邻窗口:允许前后各一个 30 秒窗口,可覆盖多数设备的时间漂移,同时把可用窗口控制在 90 秒内;
- 漂移告警:若大量用户集中在同一侧窗口命中,说明客户端普遍偏快或偏慢,应检查服务端时间同步;
- 同步时间源:服务端必须启用 NTP,时钟漂移会让整个校验体系失效;
- 恢复码兜底:时钟严重异常时,一次性恢复码是唯一可靠的逃生通道。
上线检查清单
- 密钥加密存储且不可明文读出;
- 校验前后各一个时间片,服务端已启用 NTP;
- 同一验证码只能成功一次(防重放);
- 连续失败有锁定或冷却,并提供恢复码与解绑入口。