Skip to content

Java 集成 OTP 动态口令之手机端 Microsoft Authenticator 双重验证

前言

双重认证(英语:Two-factor authentication,缩写为 2FA),又译为双重验证、双因素认证、二元认证,又称两步骤验证(2-Step Verification,又译两步验证),是一种认证方法。

场景

  1. 当你想将自己的系统暴露在公网上,但又觉得自己的系统安全认证有些欠缺,想在用户登录后,二次验证当前登录者是否是用户持有者本人时;
  2. 当用户做一些危险操作时,你想提高自己系统的安全性,于是你想到了可以在用户做危险操作前,再次验证用户密码,以确保当前操作者是用户本人。

基于以上两个场景,你很容易就想到,以下 2FA(二次验证)方案:

  1. 再一次让用户输入密码,来验证是否用户本人。但这个在登录场景不适用,同一个密码验证两次达不到目的,并且如果是密码泄漏,这种方式防不住。
  2. 集成短信验证。方案很好,就是费钱。
  3. 集成邮箱验证。这方案也还不错,挺传统的。

基于以上已有的这些,所以二次验证口令应该至少具备以下特点:

  1. 第二次验证的口令应该是动态的。这样的验证安全等级才高。不能跟密码一样是固定的,一旦泄漏就不安全了。
  2. 方案能节省经费最好。帮老板省点钱。
  3. 最好通过手机验证。移动终端时代,智能手机大行其道,二维码技术非常成熟。

那么有没有一种在手机上获取动态口令,让用户输入去验证的方式呢?答案是:有。OTP(One-time Password,也称动态口令)就是一种方式

OTP(One-time Password)动态口令

什么是 OTP?

OTP 全称叫 One-time Password, 也称动态口令,是根据专门的算法不同,可以每隔 30 秒、60 秒生成一个与时间相关的、不可预测的随机数字组合,每个口令在有效期内只能使用一次,每天可以产生 1440(60 秒间隔)个密码。

原理

动态密码的产生方式,主要是以时间差做为服务器与密代码生成器的同步条件。在需要登录的时候,就利用密代码生成器产生动态密码。

OTP 一般分为计次使用以及计时使用两种。

  • 计次使用(HOTP) 的 OTP 产出后,可在不限时间内使用;
    • HOTP(HMAC-based one-time passwords) 基于 HMAC 算法一次性密码生成器, 规范见:RFC 4226 .
    • 基于事件同步,通过某一特定的事件次序及相同的种子值作为输入,通过 HASH 算法运算出一致的密码。
  • 计时使用(TOTP) 的 OTP 则可设置密码有效时间,从 30 秒到两分钟不等,而 OTP 在进行认证之后即废弃不用,下次认证必须使用新的密码,增加了试图不经授权访问有限制资源的难度。
    • TOTP(Time-based One-time Password) 是一种从共享密钥和当前时间计算一次性密码的算法生成器。规范见:RFC 6238 .
    • 时间同步,基于客户端的动态口令和动态口令验证服务器的时间比对,一般每 30 秒产生一个新口令, 要求客户端和服务器能够十分精确的保持正确的时钟,客户端和服务端基于时间计算的动态口令才能一致。

以 TOTP 为例,如何使用动态口令认证?

主要是以下几点:

  1. 每一个用户注册系统后,后台生成一个共享密钥,加密存储到数据库中备用。
  2. 每一个用户登录系统后,在页面请求后台接口,由后台接口根据该用户的共享密钥,生成一个二维码,响应给前端,以供用户用手机扫描该二维码。
    • 二维码应该包含以下格式的内容:
    • "otpauth://totp/{}?secret={}&issuer={}"
    • 第 1 个 {} 的意思:可以填写用户的名字、或登录名。在手机客户端可以清楚的标识用户信息。
    • 第 2 个 {} 的意思:共享密钥
    • 第 3 个 {} 的意思:代表应用名称,系统名称、代号等,比如 Google。
    • 以手机端生成动态口令的应用程序 Microsoft Authenticator(安卓、苹果、linux、windows 都有对应软件) 为例,后续使用 Microsoft Authenticator 扫描二维码。
  3. 使用 Microsoft Authenticator 扫描上面步骤生成的二维码。如果你的二维码格式符合【"otpauth://totp/{}?secret={}&issuer={}"】这样的格式,手机扫描后,点击对应的记录,就能实时的看到由 6 位数字组成的动态口令。后续用户把这个输入到验证表单,提交到后台验证。这个是由手机客户端生成的。
  4. 对应的,服务端也需要根据 TOTP 算法,实时生成一个由 6 位数字组成的动态口令。
  5. 前端用户输入手机上的动态口令提交到后端服务后,后台对比手机端生成的动态口令与服务器端生成的动态口令是否一致,如果一致则验证通过,不一致则口令无效,验证失败。

以上就是大概的原理交互过程。

至于代码的编写,用现成的库算法都有,没几行代码可写的,就不贴代码了。

如果有更好的方式,欢迎分享。