双因素认证2FA
2FA 概念
认证(authentication)即是确认用户身份,密码是最常见的认证方法。但是密码容易泄露和冒充,因此越来越多的网站开始采用双因素认证(Two-factor authentication,简称 2FA)。即通过使用除密码外的其他因素,来确认用户身份,增加冒充的难度。
常用的认证因素可以分为以下几类:
- 秘密信息:只有该用户知道、其他人不知道的某种信息,比如密码。
- 个人物品:该用户的私人物品,比如身份证、钥匙、U 盾等。
- 生理特征:该用户的遗传特征,比如指纹、相貌、虹膜等等。
因素越多,证明力就越强,身份就越可靠。要求更高的的系统可以采用多因素认证(MFA)。
2FA 认证方案
常见的 2FA 认证方案有:
- 基于硬件的方式,密码 + 某种个人物品,例如 网银 U 盾、智能卡等,缺点要随身携带;
- 基于手机 SMS 的方式,密码 + 短信验证码,缺点是 容易被拦截和伪造(ss7信令漏洞),手机丢失或更换手机号成本较高;
- 基于一次性密码(One Time Password,简称OTP);
OTP 密码不易泄露,即是泄漏也难以受到重放攻击,另外其公开协议 + 高强度算法方式也难以猜测,是 2FA 方案的首选。
OTP 有两种:
- HOTP(HMAC-Based One-Time Password)基于 HMAC 的一次性密码,使用计数器计算下一个密码值。标准写入 RFC4226;
- TOTP(Time-Based One-Time Password)基于时间的一次性密码,使用时间计算下一个密码值。标准写入 RFC6238;
TOTP 从 HOTP 发展而来,目前已经成为主流的验证方式。
TOTP
使用步骤
- 用户开启双因素认证后,服务器生成一个密钥;
- 服务器提示用户扫描二维码(或其他方式),用户保存该密钥到硬件生成器或软件生成器中,此时服务器和用户拥有了相同的密钥;
- 用户登录时,手机客户端使用这个密钥和当前时间戳,生成一个哈希,有效期默认为30秒。用户在有效期内,把这个哈希提交给服务器。
- 服务器也使用密钥和当前时间戳,生成一个哈希,跟用户提交的哈希比对。只要两者不一致,就拒绝登录。
实际应用过程中,还要做到:
- 提供备用的固定哈希代码,用于 TOTP 密钥丢失的情况;
- 在第2步用户绑定密钥时,就让用户输入一次哈希,验证绑定正确,用户与服务器使用了同一个密钥。
算法原理
首先计算时间计数器 TC
,TOTP 用 TC
代替了 HOTP 中的计数器。
|
|
unixtime(now)
是当前 Unix 时间戳,unixtime(T0)
是约定的起始时间点的时间戳,默认是0
,也就是1970年1月1日。TS 则是哈希有效期的时间长度,默认是30秒。通过整除,能够保证在 30 秒内,TC
都是同一个值。
然后使用 TC
计算哈希:
|
|
HASH
就是约定的哈希函数,默认是 SHA-1。
根据TOTP的算法特性,服务器时间与 TOTP 客户端时间差如果超过 TC
,那么一定无法生成一致的哈希。实际应用中最好能够保持时间同步。
TOTP 客户端
TOTP 客户端可以分为 TOTP 硬件生成器 和 TOTP 软件生成器。软件生成器与硬件生成器相比,优势在于:
- 可以绑定多个密钥;
- 可以方便的绑定解绑;
- 时间准确性高;
常用 TOTP 软件生成器:
- Google Authenticator
- Microsoft Authenticator(可为微软系网站生成8位字符令牌,为其他网站生成6位字符令牌)
- FreeOTP
服务端 Python 实现
Python 可以选择使用 PyOTP 库,该库实现了 HOTP 和 TOTP。可以通过 pip 安装:
|
|
TOTP 示例:
|
|
HOTP 示例:
|
|
生成 base32 随机密钥:
|
|
生成 Google Authenticator 兼容链接:
|
|
Google Authenticator 需要传入账户名称和签发机构 issuer_name
参数。得到的链接可以生成二维码供 Google Authenticator 扫描。
2FA 缺点
双因素认证有一个最大的问题,那就是帐户的恢复。一旦密钥丢失,想要恢复登录,势必就要绕过双因素认证,这就形成了一个安全漏洞。除非准备两套双因素认证,一套用来登录,另一套用来恢复账户(前文所说的备用哈希代码)。