什么是 TOTP

起因

前一段时间,github 强制要求 2FA,而且不是常规的短信或邮件,而是 TOTP。需要在手机上安装一个动态密码应用(我用的是 Microsoft Authenticator),由这个应用生成动态密码。

除了 TOTP,还有更简单的 HOTP,它们都是生成动态密码的协议。

HOTP 原理

首先介绍 HOTP,一个常规的 2FA 验证流程为:

  1. 使用手机 APP 扫描一个二维码,这个二维码包含一个随机密钥。
  2. 手机和服务器都持有该密钥,且都有一个计数器变量,初始值为 0。
  3. 不是生成一个密码,而是生成一串密码。“初始密钥 + 计数器”共同构成随机种子,也就是说,初始密钥确定了,这一串密钥序列也是确定的。
  4. 手机 APP 和服务器都可以使用初始密钥和计数器生成一串密钥,需要认证时,客户端将计数器加一,算出下一个校验码,发送给服务器。服务器也将计数器加一,算出验证码与用户的输入比较,比较一致则认证通过。
  5. 由于网络原因,用户输入的验证码也许没能发送给服务器,导致客户端计数器加一,服务端计数器未变。因此服务器往往会检查接下来若干个值。服务器检查后面多少个校验码,称为 look-ahead-window,通常为 4 或 5。

用户每次认证,都要在手机上增加计数器,生成新的 code,发给服务器校验。只要客户端与服务器维持计数器进度相同,就可以一直验证。

如果客户端的计数器超前服务器太多,超过了 look-ahead-window 的长度,就只能重新扫描二维码,重新设置一套随机密钥和计数器。

TOTP 原理

知道了 HTOP 的工作原理,TOTP 就简单了,把计数器换成时间就可以了。每隔固定时间,客户端和服务器的计数器自动加一。一般用的是 unix 系统标准时间,每 30 秒计数器加一。

TOTP 是否真的有用

2FA 的目的是什么?仅仅靠密码登录为什么不行?

除了密码泄露,cookie 中存储的 session id 如果泄露,黑客都能实现远程登录,2FA 的目的就是防止这种情况。

如果服务器发现登陆 IP 或登陆设备 ID 发生了变更,就会要求用户换一种方式证明 “我是我”。

如何证明?国内网站和 APP 一般用手机短信,这是因为国内手机号强制实名,且手机是个人物品。国外有些网站使用邮箱密码,感觉没那么可靠,更像是把拦截失败的锅甩了出去。

HOTP、TOTP 这类方法则是使用上一次成功登录的历史来认证本次登录。因为只有上一次成功登录的用户才持有正确的初始密钥和计数器,才能生成正确的本次校验码。

不存在 100% 可靠的登陆验证方法,更可靠的方法必然更麻烦。2FA 让用户使用麻烦但可靠的方式认证一次,之后便可以使用不那么可靠但方便的方式登录。