我正在添加使用SMS的双因素身份验证来增强现有的登录过程。由于我没有使用物理标记,所以我想知道什么是最安全的:
随机发送8个字符串或8位数字哈希,使用某种基于时间的一次性密码(TOTP)算法生成。
我自己的注意事项如下:使用TOTP生成的散列无需存储以检查用户是否正确地输入了它们。随机生成的令牌确实需要存储并链接到用户帐户和时间戳。
然而,随机生成字符串的过程似乎更容易,并且似乎有较少的易受伤害的点。
发布于 2012-08-16 17:13:18
如果您使用高熵随机生成的服务器端秘密连接的加密散列(客户端已知的时间戳)以及用户名,我不认为该方法有任何缺陷。当然,我不会使用8位数字(例如,每1亿次随机绕过1次)或8位十六进制数(每40亿次机会中就有1次),但我会使用加密散列,并将其转换为大写-36(小写字母加数字) (1 /2万亿)或基数-64 (1 / 100万亿),并接受前8个字符(虽然最好是更多的字符)。注意,对于base64来说,对一些常用的混淆字符进行消毒对于UX可能是有意义的;例如,不要让用户区分I或l或1、O或0 (似乎是随机字符串),并可能将+、/从base64中删除。您还必须确保在用户输入time_str和user_name的屏幕上返回OTP。
另外,请确保以固定时间的方式比较time_str (否则,定时攻击可以通过尝试和错误计算出令牌),如果密码不在有效时间段内,则过期。请注意,如果您担心每100万亿的随机机会中就有1次破门而入是不够安全的,那么您还可以从IP地址跟踪错误的登录尝试,并阻止它们/要求CAPTCHA/在大约5到10次错误尝试之后限制它们。
下面是一些示例python代码:
import hashlib
import time
import base64
secret_str = 'pcA2Sh1e2ovxzjcih4OUiGKHBzytB8FaVScTo0iQ'
time_str = str(time.time())
user_name = 'drjimbob'
def get_hash_from_time_username(time_str, user_name):
hash = hashlib.sha512(secret_str+time_str+user_name).digest()
b64_hash = base64.b64_encode(hash)
# starts as 86 characters long (excluding `=` at end)
for ch in ['0','O','1','I','l','+','/', '=']:
b64_hash = b64_hash.replace(ch,'')
b64_hash = b64_hash[:8]
# overwhelming odds roughly ~1 in 10^60 it will be shorter than 8 chars
if len(b64_hash) < 8: # in very rare exception repeat the hash.
b64_hash = (b64_hash + b64_hash)[:8]
return b64_hash
def check_from_time_username(input_one_time_pass, time_str, user_name):
cur_time = time.time()
if cur_time < int(time_str): # time_str in future; user changed time_str
return False
if cur_time - 3600 > int(time_str): # time_str is more than an hour old
return False
if len(input_one_time_pass) < 8:
return False
b64_hash = get_hash_from_time_username(time_str, user_name)
is_ok = 0
for i in range(8):
is_ok += ord(b64_hash[i]) ^ ord(input_one_time_pass[i])
# bitwise compare to have constant time string comparison
return is_ok == 0发布于 2012-08-21 15:53:17
我建议您使用随机值。这是最简单的方法。在安全方面,简单是好的。
你可以用一个TOTP,但为什么要麻烦呢?(你提到它们不必存储在数据库中,但那又怎样呢?你有数据库,为什么不使用它呢?)如果您正确地实现了TOTP解决方案,它也可以是安全的,但是它更复杂,并且有更多的机会出错。看看托马斯·波宁的回答有多长。
底线:亲吻。使用随机值。
发布于 2012-08-21 13:15:29
如果您通过非加密、不安全的通道(如SMS )发送OTP,那么OTP的生成方法就无关紧要了。SMS就像外包的电子邮件,没有PGP的可能。有关这方面的信息,请参阅这篇博文:http://www.wikidsystems.com/WiKIDBlog/another-nail-for-sms-authentication/why-using-sms-for-authentication-is-a-bad-idea
https://security.stackexchange.com/questions/18796
复制相似问题