概叙
科普文:软件架构设计之应用安全【身份验证(Authentication):短信验证、图片验证、TOTP一次性密码、2FA双重身份验证等小结】-CSDN博客
OTP(一次性密码)
一次性密码(One Time Password, 简称 OTP),亦称动态密码,是一种高效简单又比较安全的密码生成算法,在我们的生活以及工作中随处可见。
动态密码是指随着某一事件(密码被使用、一定的时间流逝等)的发生而重新生成的密码,因为动态密码本身最大优点是防重复执行攻击(replay attack),它能很好地避免类似静态密码可能被暴力破解等的缺陷,现实运用中,一般采用“静态密码+动态密码”相结合的双因素认证,我们也称二步验证。
银行的电子银行口令卡。
Google 的 Authenticator APP。
如上图所示,OTP核心在于如何能够让用户手机应用产生的验证码和服务器产生的验证码一致,或者是在一定范围内一致(这也是RFC4266 和 RFC6238协议解决的核心问题)。
可以保证校验段和被校验端具有相同的输出。用于离线处理的情况,只需要事先约定好密钥。
- 一次性使用的密码,用于增强身份验证安全性,有效期短且唯一。
- OTP一次性密码是一种动态生成的密码,通常基于时间(TOTP)或事件(HOTP)生成,且每次使用后失效。可以通过多种方式传递,如短信、邮件、认证应用(如 Google Authenticator)或硬件令牌。
- 应用场景:登录验证、支付确认、敏感操作授权等。
- OTP生成方式:通常基于算法生成,包括TOTP和HOTP两种方式。 生成过程不依赖外部网络,具有更高的独立性。
- TOTP(基于时间的 OTP,计时使用):根据当前时间和共享密钥生成,基于RFC6238协议。
- HOTP(基于事件的 OTP,计次使用):根据计数器值和共享密钥生成,基于RFC4266 协议。
HOTP(基于哈希的一次性密码)
- 事件驱动型,基于计数器(Counter)和共享密钥生成密码,公式为:
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
。 - 每认证一次,计数器自增,密码失效。
TOTP(基于时间的一次性密码)
- 时间驱动型,以时间窗口(如30秒)代替计数器,公式为:
TOTP(K) = HOTP(K, T)
,其中T = floor(UnixTime / 时间步长)
。 - 密码随时间周期性刷新(如Google Authenticator)。
TOTP 和 HOTP 的对比
对比维度 | TOTP | HOTP |
---|---|---|
生成方式 | 基于时间窗口(每 30 秒生成一个密码) | 基于计数器递增(每次计数器增加生成一个密码) |
时间依赖性 | 高:需要设备和服务器时间同步 | 低:不依赖时间同步 |
计数器管理 | 无:时间窗口自动递增 | 需要:设备和服务器需要维护一致的计数器 |
适用场景 | 移动应用、实时验证(如 Google Authenticator) | 硬件令牌、离线验证(如银行 U 盾) |
安全性 | 高:密码短暂有效,且基于时间窗口 | 高:密码唯一且短暂有效,但依赖计数器同步 |
用户体验 | 好:无需手动输入密钥,设备本地生成密码 | 较差:可能需要手动输入密码或处理计数器同步 |
复杂性 | 低:设备和服务器只需同步时间 | 高:需要管理计数器,同步逻辑复杂 |
- TOTP 更适合移动应用和实时验证场景。
- HOTP 更适合硬件令牌和离线验证场景。
- 两者都是高安全性的 OTP 实现方式,但适用场景和管理复杂性不同。
选择建议
- 选择 TOTP:如果你的应用需要实时验证且设备支持时间同步(如移动应用),TOTP 是更好的选择。
- 选择 HOTP:如果你的应用需要离线验证或硬件令牌支持(如银行 U 盾),HOTP 是更好的选择。
HOTP(基于哈希的一次性密码)
协议文档:RFC 4266: The gopher URI Scheme
RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm
HOTP 算法,全称是“An HMAC-Based One-Time Password Algorithm”,是一种基于事件计数的一次性密码生成算法,详细的算法介绍可以查看 RFC4266。
其实 HOTP 的算法比我在阅读算法前所想象的要简洁得多,而且仍然足够强健。算法本身巧妙利用了加密算法对共享密钥和计数器进行加密,确保这两个动态密码生成因子不被篡改,接着通过一个 truncate 函数随机得到一个最长 10 位的 10 进制整数,最终实现对 1 - 10 位长度动态密码的支持。算法本身的简洁也确保了算法本身可以在各种设备上实现。
其实算法本身非常简单,算法本身可以用两条简短的表达式描述:
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
PWD(K,C,digit) = HOTP(K,C) mod 10^Digit
-
K 代表我们在认证服务器端以及密码生成端(客户设备)之间共享的密钥,在 RFC 4226 中,作者要求共享密钥最小长度是 128 位,而作者本身推荐使用 160 位长度的密钥
-
C 表示事件计数的值,8 字节的整数,称为移动因子(moving factor),需要注意的是,这里的 C 的整数值需要用二进制的字符串表达,比如某个事件计数为 3,则C是
"11"
(此处省略了前面的二进制的数字0) -
HMAC-SHA-1 表示对共享密钥以及移动因子进行 HMAC 的 SHA1 算法加密,得到 160 位长度(20字节)的加密结果
-
Truncate 即截断函数,由于 SHA-1 算法是既有算法,不是我们讨论重点,故而 Truncate 函数就是整个算法中最为关键的部分。
-
digit 指定动态密码长度,比如我们常见的都是 6 位长度的动态密码
密码失效机制
从上面的分析可以看到,一个动态密码的生成,取决于共享密钥以及移动因子的值,而共享密钥是保持不变的,最终就只有移动因子决定了密码的生成结果。所以在 HOTP 算法中,要求每次密码验证成功后,认证服务器端以及密码生成器(客户端)都要将计数器的值加1,已确保得到新的密码。
但是在这里就会引入一个问题,假如认证服务器端与密码生成器之间由于通信故障或者其他意外情况,导致两边计数器的值不同步了,那么就会导致两边生成的密码无法正确匹配。为了解决这个问题,算法在分析中建议认证服务器端在验证密码失败后,可以主动尝试计数器减1之后重新生成的新密码是否与客户端提交密码一致,如果是,则可以认定是客户端计数器未同步导致,这种情况下可以通过验证,并且要求客户端重新同步计数器的值。
出了上面提到的计数器不同步的问题,我另外想的是,如果客户有多个密码生成器(假设 iPad 和 iPhone)为同个账号生成密码,那么计数器在多个设备间的同步可能就需要另外考虑的方案了。
HOTP原理:
- HOTP 是一种基于计数器的 OTP 生成算法,密码由计数器值递增生成。
- 用户设备和服务器预先共享密钥,每次计数器递增时生成新的密码。
HOTP核心流程:
- 用户设备和服务器预先共享密钥。
- 用户设备根据当前计数器值生成 OTP。
- 用户输入 OTP,服务器验证是否与当前计数器值生成的密码匹配。
- 服务器验证成功后,计数器递增。
HOTP优点:
- 不依赖时间同步:适合离线或时间同步困难的场景。
- 高安全性:密码唯一且短暂有效。
HOTP缺点:
- 需要管理计数器:设备和服务器的计数器必须保持一致。
- 计数器同步可能复杂:如设备离线时可能无法生成密码。
HOTP应用场景:
- 硬件令牌(如 YubiKey)的 OTP 生成。
- 离线环境下的身份验证。
HOTP注意事项:
- 确保设备和服务器的计数器同步。
- 处理计数器递增的逻辑(如支持计数器回滚)。
TOTP(基于时间的一次性密码)
协议文档:RFC 6238: TOTP: Time-Based One-Time Password Algorithm
RFC 6238: TOTP: Time-Based One-Time Password Algorithm
TOTP 算法,全称是 TOTP: Time-Based One-Time Password Algorithm,其基于 HOTP 算法实现,核心是将移动因子从 HOTP 中的事件计数改为时间差。完整的 TOTP 算法的说明可以查看 RFC6238,其公式描述也非常简单:
TOTP = HOTP(K, T) // T is an integer
and represents the number of time steps between the initial counter
time T0 and the current Unix time
More specifically, T = (Current Unix time - T0) / X, where the
default floor function is used in the computation.
通常来说,TOTP 中所使用的时间差都是当前时间戳,TOTP 将时间差除以时间窗口(密码有效期,默认 30 秒)得到时间窗口计数,以此作为动态密码算法的移动因子,这样基于 HOTP 算法就能方便得到基于时间的动态密码了。
TOTP原理:
- TOTP 是一种基于时间窗口的 OTP 生成算法,密码会随时间变化。
- 时间窗口通常为 30 秒,每隔 30 秒生成一个新密码。
- 用户设备(如手机)和服务器通过预共享密钥和时间同步生成相同的密码。
TOTP核心流程:
- 用户设备和服务器预先共享密钥。
- 用户设备根据当前时间生成 OTP。
- 用户输入 OTP,服务器验证是否与当前时间窗口内的密码匹配。
TOTP优点:
- 高安全性:密码唯一且短暂有效。
- 无需网络:设备本地生成密码。
- 用户体验好:无需手动输入长密钥。
TOTP缺点:
- 依赖时间同步:设备和服务器时间必须一致,否则可能导致验证失败。
- 需要设备支持时间同步功能。
TOTP应用场景:
- 移动应用的登录验证(如 Google Authenticator)。
- 银行、支付平台的高安全需求场景。
TOTP注意事项:
- 确保设备和服务器时间同步。
- 处理时间误差(如允许 ±1 分钟的时间偏移)。