【发布时间】:2015-06-10 03:53:34
【问题描述】:
我一直在阅读它的工作原理,它在减慢暴力破解尝试方面确实很酷,但它仍然感觉不安全。
假设有人窃取了我的数据库数据,包括我所有的用户密码哈希,并且知道我使用password_hash 对我的密码进行哈希处理。难道他不能用他的字典和password_verify 遍历我的密码来获得访问权限吗?
在对密码进行哈希处理之前添加另一种盐是一种好习惯吗?
【问题讨论】:
标签: php security encryption
我一直在阅读它的工作原理,它在减慢暴力破解尝试方面确实很酷,但它仍然感觉不安全。
假设有人窃取了我的数据库数据,包括我所有的用户密码哈希,并且知道我使用password_hash 对我的密码进行哈希处理。难道他不能用他的字典和password_verify 遍历我的密码来获得访问权限吗?
在对密码进行哈希处理之前添加另一种盐是一种好习惯吗?
【问题讨论】:
标签: php security encryption
补充@adeneo的答案,
bcrypt、pbkdf2、scrypt 和现代密码散列策略的要点是要慢。
是的,如果您从数据库 (SQLi) 获得生成的哈希值,您可以尝试输入密码并尝试验证每个密码。
但是,只需尝试密码 有点轻描淡写。让我们看一些数学。
password_hash() 与 bcrypt 的默认成本大约需要 0.1 秒来散列密码。这意味着验证密码哈希大约需要 0.1 秒。
英语中有大约 1,000,000 个单词。要尝试每一个,您需要验证 1,000,000 次。以每 0.1 秒计算,即 100,000 秒(约 27 小时)。
27 小时 1,000,000 次猜测泄露的单个密码哈希。由于每个散列都带有一个盐,攻击者需要对每个泄露的散列重复这些猜测。
如果您的数据库有 100 万用户,仅针对密码尝试字典就需要 76,000 个 CPU 年(1 个 CPU 76,000 年,76,000 个 CPU 1 年,或者两者之间的任何交易)。
从角度来看,25 GPU cluster 上的 md5()每秒可以进行大约 180,000,000,000 次猜测。要将这百万个字典条目与数据库中的百万个哈希值进行对比,大约需要 5.5 秒。
137 GPU 秒与 76,000 CPU 年。 这就是使用 bcrypt 的原因。
【讨论】:
不,如果有人窃取了数据库,他们可能已经可以访问所有内容,但如果说他们没有,他们只会得到哈希值。
哈希不能用于密码字段,因为它会再次被哈希并且与数据库中的哈希不匹配,需要实际的密码,而不是哈希。
使用password_verify 不会为您提供原始密码,它只会检查密码是否与哈希匹配,这意味着您仍然必须拥有原始密码和哈希才能看看它们是否匹配,所以只有散列会让你无处可去。
$is_correct = password_verify($password_typed_by_user, $hash_gotten_from_db); // bool
归根结底,没有什么是安全的,哈希很可能会被暴力破解、彩虹表或单词列表/字典等破坏。但这无关紧要,因为它通常需要大量时间和精力,而且可能无论是否使用password_hash,都使用任何哈希完成。
使用更新的散列和强密码是最好的防御,如果用于散列密码的算法有点慢,则遍历单词列表并散列每个单词需要更长的时间。同样,如果密码很长或有特殊字符,则检查所有达到该长度的字符等需要更长的时间。
添加更多的盐没有任何作用。盐不是秘密,它只是您添加的自定义内容,以避免哈希值被预先计算的查找表(如彩虹表)破解。
盐通常与哈希一起存储,或者在不同字段的同一数据库中,或者在使用 PHP 的 password_hash 时,它实际上只是连接到哈希,看起来像 mysalt.hash。
一般来说,应该使用随机盐,以防止预先生成散列表,这就是所需要的,盐不是秘密,除了使函数生成散列之外它不会增加安全性独一无二,因此无法大规模复制。
【讨论】:
password_verify来检查猜测的密码是否等于hash? - 在散列之前添加额外的盐会改善它吗?
这总是一个问题。让我们希望您的用户使用的密码不在字典或前 100 个使用的密码中。您有责任强制使用在字典中不易找到的更强大的密码。
【讨论】: