什么是 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 让用户使用麻烦但可靠的方式认证一次,之后便可以使用不那么可靠但方便的方式登录。