两步验证(2FA)应用如 Google Authenticator、Microsoft Authenticator 的核心原理是基于TOTP(Time-Based One-Time Password,基于时间的一次性密码)算法,该算法源自HOTP(HMAC-based One-Time Password,基于 HMAC 的一次性密码)算法。
一、核心组成要素
| 要素 | 说明 |
|---|---|
| 共享密钥 (Secret Key) | 服务端与客户端预先协商的唯一密钥,通常为 32 位 Base32 编码字符串,通过二维码或手动输入方式共享 |
| 时间同步 | 双方使用 Unix 时间戳 (从 1970 年 1 月 1 日 00:00:00 UTC 开始计算的秒数),以30 秒为一个时间窗口 |
| HMAC 算法 | 通常使用 HMAC-SHA1 哈希函数,将密钥与时间值结合生成哈希值 |
| 一次性密码 (OTP) | 最终生成的 6-8 位数字密码,每 30 秒自动更新 |
二、工作流程详解
1. 初始绑定阶段
- 用户在服务端 (如 GitHub、Google 账户) 启用两步验证
- 服务端生成唯一的共享密钥,并以二维码形式展示 (包含密钥、账户名、服务名等信息)
- 用户使用 Authenticator 应用扫描二维码,将密钥安全存储在本地设备中
- 服务端同时将该密钥与用户账户关联并保存到数据库
2. 验证码生成阶段 (客户端)
-
获取当前 Unix 时间戳,计算时间步长计数器:
T = floor(current_time / 30) -
使用HMAC 算法计算哈希值:
HMAC-SHA1(密钥, T) -
对哈希值进行截断处理(Truncate):
- 取哈希值最后一个字节的低 4 位作为偏移量
- 从偏移量位置取 4 个字节,组成 32 位整数
- 对该整数取模 10^6 (或 10^8),得到 6 位 (或 8 位) 数字密码
-
每 30 秒重复上述过程,生成新的验证码
3. 验证阶段 (服务端)
- 用户输入账户密码后,被要求提供 Authenticator 中的 6 位验证码
- 服务端从数据库读取与该账户关联的共享密钥
- 使用与客户端完全相同的TOTP 算法生成验证码
- 验证用户输入的验证码与服务端生成的是否一致
- 验证通过则允许登录,否则拒绝访问
三、HOTP 与 TOTP 的关系
-
HOTP:基于计数器的一次性密码算法,公式为
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))- K: 共享密钥
- C: 计数器,每次验证成功后递增
-
TOTP:是 HOTP 的时间版本,将计数器 C 替换为基于时间的计数器 T
- 公式:
TOTP(K) = HOTP(K, T),其中T = floor(current_time / X)(X 通常为 30 秒)
- 公式:
四、关键安全特性
- 无需网络连接:验证码生成完全在本地设备完成,不依赖网络
- 时效性:验证码仅在 30 秒内有效,超时自动失效
- 唯一性:每个时间窗口生成的验证码都是唯一的,无法重复使用
- 双因素保障:即使密码泄露,攻击者还需获取用户设备或密钥才能登录
- 多设备同步:部分应用 (如 Microsoft Authenticator、新版 Google Authenticator) 支持加密同步密钥到云端,方便设备更换
五、时间同步的重要性
TOTP 算法依赖服务端与客户端的时间高度同步。如果设备时间与服务端时间偏差超过 30 秒,生成的验证码将不匹配。大多数应用会允许 **±1 个时间窗口 ** 的误差 (即 90 秒内有效),以应对轻微的时间偏差。
总结
Authenticator 应用的核心原理是通过预共享密钥和时间同步,使用TOTP 算法生成一次性验证码,实现 "你知道的 (密码)+ 你拥有的 (设备)" 的双因素认证,大幅提升账户安全性。