2FA验证原理
什么是 2FA
2FA(Two-Factor Authentication),即双因素认证,是一种认证方式,通过用户名和密码之外的另一种因素来认证用户。例如:
- 短信验证码
- 邮件验证码
- 手机验证码
- 指纹识别
- 人脸识别
- 令牌
Authenticator App
Authenticator App 是一种 2FA 的实现方式,它通常是一个手机应用程序,用户可以在手机上安装这个应用程序,然后使用应用程序来生成验证码。
例如 Google Authenticator
Authenticator App 的核心基石是 TOTP(Time-Based One-Time Password,基于时间的一次性密码)算法。它的核心思想是:服务器和手机 App 在相同时间,使用相同密钥,计算出相同的数字
如何绑定账户?
绑定过程的本质是“共享密钥(Shared Secret)”的传递
- 生成密钥,开启 2FA 时,服务器会生成一个密钥,通常是一串 Base32 的字符串
- 将密钥发送给用户,服务端将这个密钥、用户、发卡方(例如 Github)组合在一起,生成一个特定的 URL,并生成二维码,供用户扫码绑定
- App 接收,用户扫码绑定,App 解析后并将密钥保存到本地。至此,服务器和你的手机都拥有了同一份完全相同的密钥
如何生成验证码?
- 获取 Time Step。App 获取当前手机系统的 Unix 时间戳。因为时间每秒都在变,为了让验证码保持一段时间有效,算法引入了“步长”。例如 60 秒一变
- HMAC 哈希计算。使用共享密钥(Secret)作为 Key,当前的计数器(Counter)作为 Data,进行 HMAC-SHA1 哈希计算,得到一个 20 字节的哈希值
- 截断。由于 20 字节的哈希值太长,算法会通过一种动态截断机制,从中提取出 4 个字节,转化为一个十进制整数
- 取模生成 6 位数。将截断后的整数取模 1_000_000,得到一个 6 位数,即为验证码
如何验证验证码?
- 服务端生成自己的验证码
- 客户端生成自己的验证码
- 服务端和客户端的验证码进行对比,如果一致,则验证通过
FAQ
为什么离线也能生成验证码?
因为 TOTP 算法是基于时间的一次性密码,客户端和服务端不需要实时通信,所以即使手机离线,也可以生成验证码
为什么手机时间不准也能生成验证码?
Authenticator App 自己去向谷歌的 NTP 服务器请求一次标准的 UTC 时间,计算出手机本地硬件时钟与标准时间的差值(Offset)。在后续生成验证码时,App 会在本地时间上自动加上这个差值,从而在手机时间不准的情况下,依然能生成正确的验证码