双因子(多因子认证)
双因子认证多增加了一步一次性密码校验,更加安全。
有两种方式来生成一次性密码:
-
SMS-based(基于短信):每次用户登录,都会从注册手机那里收到一条包含一次性密码的短信
-
TOTP-based(基于时间):当开启双因子认证后,用户需要用特定的手机应用APP扫描二维码,这个应用程序会不断为用户生成一次性密码
TOTP工作流程
其中存在3个问题点:
-
应用程序如何用密钥(Secret Key)和计数器(Counter)生成一次性密码(One-Time -Password)
-
计数器如何更新?服务器如何保持跟踪计数器?
-
服务器怎么把密钥分享给应用程序?
第一个问题的答案就在HOTP算法中
HOTP又是什么呢
HMAC-Based One-Time Password. 该算法由IETF(互联网工程任务组)发布在RFC4226
使用方法:
-
从一个密钥和计数器生成HMAC哈希
hmac_result= HMAC-SHA-1(secret-key, counter)
-
通过上一步得到的输出是20个字节长的字符串,这个长字符串并不适合用作一次性密码,所以需要对它进行截断
int offset = hmac_result[19] & 0xf;
int bin_code = (hmac_result)[offset] & 0x7f << 24 | (hmac_result[offset+1] & 0xff) << 16 | (hmac_result[offset+2] & 0xff) << 8 | (hmac_result[offset+3] & 0xff) ;
finalOTP = (bin_code % (10 ^ numberOfDigitsRequiredInOTP));
SHA-1 HMAC bytes(Example)
-------------------------------------------------------------
| Byte Number |
-------------------------------------------------------------
|00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|
-------------------------------------------------------------
| Byte Value |
-------------------------------------------------------------
|1f|86|98|69|0e|02|ca|16|61|85|50|ef|7f|19|da|8e|94|5b|55|5a|
-------------------------------***********----------------++|
-
最后一个字节,hmac_result[19]的16进制是0x5a,低4位bit是0xa
-
offset 为字节0xa,十进制为10
-
从第10位开始算4个字节,得到0x50ef7f19,即动态二进制码,DBC1
-
DBC1的 MSB 是0x50,所以DBC2=DBC2
-
HOTP = DBC2 % 10^6=872921(6位动态码)
TOTP
TOTP
使用HOTP
算法获得一次性密码,两者不同的是TOTP使用Time
时间参数替换counter
(计数器),这样就解决了第二个问题。
与其初始化counter
并跟踪它,不如使用time
参数去获取OTP
(一次性密码)。因此服务器和手机并须同步时间,这样就不用去跟踪counter了。
当然为了解决服务器和手机时区不同步的问题,使用Unix timestamp
,这样就不用关注时区了。
但是Unix Time是以秒计算的,每秒都在变化,意味着生成的密码也将每秒变化,这样就不太好了。因此,需要设置一个significant interval
间隔区间来更新密码。
Goole Authenticator APP每30秒更改一次密码
counter = currentUnixTime / 30
解决了第二个问题,我们接下来用QR code
(二维码)来解决第三个同步密码问题。
QR code
虽然我们可以要求用户直接将密钥输入到他们的手机应用程序中,但出于安全原因,我们希望使密钥相当长,要求用户输入如此长的字符串不会是一种用户友好的体验。
现在手机都配置了摄像头,可以要求用户通过它来扫描QR code获取密码。我们要做的就说把密码转换成QR code展示给用户。
到现在3个问题都解决了,那么如何在程序中实现TOTP呢?
实现TOTP
有一些免费的手机程序(如Google Authenticator APP、Authy等),因此创建你自己的手机APP并不是必须的。
-
当用户请求开启双因子认证
-
服务器生成一个长度为20字节的密钥 secretKey = generateSecretKey(20)
-
为特定用户保存secret key到数据库中saveUserSecretKey(userId, secretKey)
-
把secret key转换成图片二维码image.qrCode = convertToQrCode(secretKey)
-
把图片二维码作为响应发送给用户responseresponse(qrCode)
-
用户扫描二维码获得secret key,用secret key、当前Unix time和HOTP算法,手机程序会生成动态密码
-
用户输入生成的动态密码
-
服务器从数据库中获取指定用户的secret key = getSecretKeyOfUser(userId)
-
如果服务器生成的动态密码和用户输入的相同,那么就可以为用户开启双因子认证。if (codeTypedByUser == getHOTP(secretKey, currentUnixTime / 30)) { enableTwoFactorAuthentication(userId);}
-
现在,在每次登录操作之后,我们需要检查这个特定用户是否启用了双因素身份验证。如果启用,那么我们要求在应用程序中显示一次性密码。如果输入的密码是正确的,那么只有这样才能对用户进行身份验证。
参考
-
RFC 4226 - HOTP: An HMAC-Based One-Time Password Algorithm (ietf.org)
-
RFC 6238 - TOTP: Time-Based One-Time Password Algorithm (ietf.org)
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)