Skip to content

2FA验证原理

什么是 2FA

2FA(Two-Factor Authentication),即双因素认证,是一种认证方式,通过用户名和密码之外的另一种因素来认证用户。例如:

  1. 短信验证码
  2. 邮件验证码
  3. 手机验证码
  4. 指纹识别
  5. 人脸识别
  6. 令牌

Authenticator App

Authenticator App 是一种 2FA 的实现方式,它通常是一个手机应用程序,用户可以在手机上安装这个应用程序,然后使用应用程序来生成验证码。

例如 Google Authenticator

Authenticator App 的核心基石是 TOTP(Time-Based One-Time Password,基于时间的一次性密码)算法。它的核心思想是:服务器和手机 App 在相同时间,使用相同密钥,计算出相同的数字

如何绑定账户?

绑定过程的本质是“共享密钥(Shared Secret)”的传递

  1. 生成密钥,开启 2FA 时,服务器会生成一个密钥,通常是一串 Base32 的字符串
  2. 将密钥发送给用户,服务端将这个密钥、用户、发卡方(例如 Github)组合在一起,生成一个特定的 URL,并生成二维码,供用户扫码绑定
  3. App 接收,用户扫码绑定,App 解析后并将密钥保存到本地。至此,服务器和你的手机都拥有了同一份完全相同的密钥

如何生成验证码?

OTP=TOTP(Secret,Time)\text{OTP} = \text{TOTP}(\text{Secret}, \text{Time})

  1. 获取 Time Step。App 获取当前手机系统的 Unix 时间戳。因为时间每秒都在变,为了让验证码保持一段时间有效,算法引入了“步长”。例如 60 秒一变 Counter=Current Time060\text{Counter} = \lfloor \frac{\text{Current Time} - 0}{60} \rfloor
  2. HMAC 哈希计算。使用共享密钥(Secret)作为 Key,当前的计数器(Counter)作为 Data,进行 HMAC-SHA1 哈希计算,得到一个 20 字节的哈希值
  3. 截断。由于 20 字节的哈希值太长,算法会通过一种动态截断机制,从中提取出 4 个字节,转化为一个十进制整数
  4. 取模生成 6 位数。将截断后的整数取模 1_000_000,得到一个 6 位数,即为验证码

如何验证验证码?

  1. 服务端生成自己的验证码
  2. 客户端生成自己的验证码
  3. 服务端和客户端的验证码进行对比,如果一致,则验证通过

FAQ

为什么离线也能生成验证码?

因为 TOTP 算法是基于时间的一次性密码,客户端和服务端不需要实时通信,所以即使手机离线,也可以生成验证码

为什么手机时间不准也能生成验证码?

Authenticator App 自己去向谷歌的 NTP 服务器请求一次标准的 UTC 时间,计算出手机本地硬件时钟与标准时间的差值(Offset)。在后续生成验证码时,App 会在本地时间上自动加上这个差值,从而在手机时间不准的情况下,依然能生成正确的验证码