TOTP 是什么
TOTP(基于时间的一次性口令,RFC 6238)由 HOTP(RFC 4226)加上时间因子演化而来:客户端与服务端共享一个密钥,双方用「当前时间片编号」作为计数器做 HMAC 运算,再截取为固定位数,于是每 30 秒自动换一个六位码。它属于「持有因素」,常与口令组合成双因素认证。安全性取决于三件事:共享密钥是否保密、服务端是否按窗口校验并防重放、系统时钟是否准确。
基本信息
| 标准 | RFC 6238(TOTP),依赖 RFC 4226(HOTP) |
|---|---|
| 共享密钥 | Base32 编码,常见 16 或 32 字符;等同于长期凭据,必须与服务端一同加密保存 |
| 默认参数 | 时间步长 30 秒、输出 6 位、HMAC-SHA1(可与服务端约定 SHA256/SHA512) |
| 时钟要求 | 客户端与服务端时间偏差需在允许窗口内,服务器应启用 NTP 同步 |
| 绑定方式 | otpauth://totp/发行方:账号?secret=...&issuer=...&period=30&digits=6 的密钥 URI,通常由二维码承载 |
| 常见工具 | oathtool(Linux 命令行)、Google Authenticator、Microsoft Authenticator、各语言 TOTP 库 |
命令行生成与校验
命令行生成与校验
# 生成当前动态码(-b 表示密钥为 base32)
oathtool --totp -b JBSWY3DPEHPK3PXP
# 每隔 5 秒打印一次,观察 30 秒步长的切换
watch -n 5 'oathtool --totp -b JBSWY3DPEHPK3PXP'
# 校验:允许前后各 1 个时间窗(-w 1)
oathtool --totp -b JBSWY3DPEHPK3PXP -w 1 --now="2026-10-13 10:00:00 UTC"
# 使用 SHA256 摘要(需与服务端参数一致)
oathtool --totp=sha256 -b JBSWY3DPEHPK3PXP校验参数与建议
| 参数 | 含义 | 建议取值与原因 |
|---|---|---|
| 时间步长 | 每个动态码的有效秒数 | 30 秒为标准值;加大步长会扩大重放窗口 |
| 校验窗口 | 允许前后偏移的时间片数量 | ±1 个时间片足以容忍网络与时钟抖动,窗口越大被爆破的空间越大 |
| 码长度 | 输出位数 | 6 位为标准;6 位码在窗口内只有有限次尝试机会,因此必须配合失败次数限制 |
| 摘要算法 | HMAC 使用的哈希 | SHA1 兼容性最好;新系统可用 SHA256,但客户端必须支持 |
| 尝试限制 | 同一账号的失败次数上限 | 必须设置,否则 6 位码在有效窗口内可被在线穷举 |
服务端实现要点
- 密钥加密存储:TOTP 密钥与口令散列同等级别保护,泄露即等于双因素失效
- 防重放:记录每个账号最近一次成功校验的时间片编号,同一编号内的重复提交一律拒绝
- 绑定与重置走身份核验:重新绑定需二次核验(如口令 + 邮箱/短信),并留存操作日志
- 备用恢复码:每人预生成一次性恢复码并单独保管,避免手机丢失后账号锁死
- 时钟同步:服务器启用 NTP 并监控时间偏差,客户端提示用户开启自动时间
- 失败计数与锁定:连续失败触发延迟或锁定,并生成安全告警事件
TOTP 不能抵御实时钓鱼:代理页面可在用户输入后立即转发动态码。面向高价值账号,优先级应放在 FIDO2/WebAuthn 这类绑定来源的抗钓鱼方案上,TOTP 作为兼容性更好的过渡选择。