Reading Notes - RFC4226 RFC6238
关于OTP的两个RFC
[RFC4226]HOTP: An HMAC-Based One-Time Password Algorithm
[RFC6238]TOTP: Time-Based One-Time Password Algorithm
符号定义
符号 | 描述 |
---|---|
C | 计数器值(8字节)。计数器值必须在服务端和客户端之间同步 |
K | 服务端和客户端之间的共享密钥。每个客户端拥有唯一的共享密钥 |
T | 次数限制参数。如果用户请求超过T次,服务端拒绝服务 |
s | 重新同步参数。服务端尝试验证s个连续的计数器值 |
Digit | 数字个数 |
生成HOTP
Step 1
生成SHA-1散列值,长度为20字节
HS = HMAC-SHA-1(K,C)
Step 2
生成4字节的动态截取串
Sbits = DT(HS)
DT(String) // String = String[0]...String[19]
Let OffsetBits be the low-order 4 bits of String[19]
Offset = StToNum(OffsetBits) // 0 <= OffSet <= 15
Let P = String[OffSet]...String[OffSet+3]
Return the Last 31 bits of P
Step 3
计算HOTP值
Snum = StToNum(Sbits)
// 将二进制串转换为整数(0..2^{31}-1)
D = Snum mod 10^Digit
Digit值应该大于等于7
验证HOTP
客户端自增计数器,生成HOTP值;
服务端收到该值,首先自增计数器,然后计算对比;
如果不匹配,执行重新同步协议,也就是将计数器继续向前试s次;
如果重新同步失败,服务器请求再次认证;
如果验证次数超过T次,那么锁住账号,通知用户。
安全性考虑
对HOTP最可能的攻击方式是暴力破解,所以对s和T的选择需要考虑。
攻击成功的概率可以形式化为:
Sec = sT/10^Digit
所以s和T值不能太大,Digit值至少为7。
另外为了保护用户隐私,以及防止重放攻击,安全的信道也是必须的,比如HTTPS。
共享密钥管理
确定性生成
通过主密钥生成共享密钥,在需要的时候实时生成。
好处是可以避免暴露共享密钥的风险;缺点是如果主密钥泄露,共享密钥也就暴露了。
随机生成
随机生成密钥,立即持久化存储,以备之后使用。
安全的存储和使用共享密码非常重要。
生成TOTP
TOTP是HOTP的一个变种,也就是用当前时间做为计数器。
TOTP = HOTP(K, T)
T = (Current Unix Time - T0) / X
此处的X表示时间步长
另外HMAC-SHA-1可以考虑更新为HMAC-SHA-256或HMAC-SHA-512。
验证TOTP
服务端收到客户端发来的TOTP值,立即根据当前服务端的时间计算TOTP值,然后进行匹配。
由于存在网络传输的延迟,对于服务端来说客户端发来的值可能是上一个时间窗的,所以我们应该设置一个可以接受的延迟时间窗,我们建议最多允许一个延迟时间窗。
时间步长的选择要综合考虑安全性和可用性,这里建议30秒。
另外,一个时间窗的OTP值一旦验证成功,那么对于该时间窗之后的验证尝试必须拒绝。