freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

TOTP时间密码算法
2024-03-25 19:00:04

双因子(多因子认证)

1711364227_660158832b764743968f1.png!small?17113642278131711364239_6601588f3eb33a5ec34d8.png!small?1711364239351

双因子认证多增加了一步一次性密码校验,更加安全。

有两种方式来生成一次性密码:

  1. SMS-based(基于短信):每次用户登录,都会从注册手机那里收到一条包含一次性密码的短信

  2. TOTP-based(基于时间):当开启双因子认证后,用户需要用特定的手机应用APP扫描二维码,这个应用程序会不断为用户生成一次性密码

TOTP工作流程

1711364252_6601589cd8bcef28f8025.png!small?1711364253058

其中存在3个问题点:

  1. 应用程序如何用密钥(Secret Key)和计数器(Counter)生成一次性密码(One-Time -Password)

  2. 计数器如何更新?服务器如何保持跟踪计数器?

  3. 服务器怎么把密钥分享给应用程序?

第一个问题的答案就在HOTP算法中

HOTP又是什么呢

HMAC-Based One-Time Password. 该算法由IETF(互联网工程任务组)发布在RFC4226

使用方法:

  1. 从一个密钥和计数器生成HMAC哈希

hmac_result= HMAC-SHA-1(secret-key, counter)

  1. 通过上一步得到的输出是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|
-------------------------------***********----------------++|
  1. 最后一个字节,hmac_result[19]的16进制是0x5a,低4位bit是0xa

  2. offset 为字节0xa,十进制为10

  3. 从第10位开始算4个字节,得到0x50ef7f19,即动态二进制码,DBC1

  4. DBC1的 MSB 是0x50,所以DBC2=DBC2

  5. HOTP = DBC2 % 10^6=872921(6位动态码)

TOTP

Time-Based One-Time Password,发布在RFC6238by IETF.

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并不是必须的。

  1. 当用户请求开启双因子认证

  2. 服务器生成一个长度为20字节的密钥 secretKey = generateSecretKey(20)

  3. 为特定用户保存secret key到数据库中saveUserSecretKey(userId, secretKey)

  4. 把secret key转换成图片二维码image.qrCode = convertToQrCode(secretKey)

  5. 把图片二维码作为响应发送给用户responseresponse(qrCode)

  6. 用户扫描二维码获得secret key,用secret key、当前Unix time和HOTP算法,手机程序会生成动态密码

  7. 用户输入生成的动态密码

  8. 服务器从数据库中获取指定用户的secret key = getSecretKeyOfUser(userId)

  9. 如果服务器生成的动态密码和用户输入的相同,那么就可以为用户开启双因子认证。if (codeTypedByUser == getHOTP(secretKey, currentUnixTime / 30)) { enableTwoFactorAuthentication(userId);}

  10. 现在,在每次登录操作之后,我们需要检查这个特定用户是否启用了双因素身份验证。如果启用,那么我们要求在应用程序中显示一次性密码。如果输入的密码是正确的,那么只有这样才能对用户进行身份验证。

参考

# 密码安全 # 一次性登录 # 多因子认证MFA
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录