PHP password_verify 真的安全吗?再加点盐?

Is PHP password_verify really secure? Add another salt?

我一直在阅读它是如何工作的,它在减慢暴力破解尝试方面真的很酷,但它仍然让人感觉不安全。

假设有人窃取了我的数据库数据,包括我所有的用户密码散列值,并且知道我使用 password_hash 来散列我的密码。他不能用他的字典和 password_verify 循环遍历我的密码来获得访问权限吗?

在对密码进行哈希处理之前添加另一种盐是好的做法吗?

不,如果有人窃取了数据库,他们可能已经可以访问所有内容,但说他们没有,他们得到的只是哈希值。

密码字段中不能使用散列,因为它会被再次散列并且与数据库中的散列不匹配,需要实际密码,而不是散列。

使用 password_verify 不会给你原始密码,它会检查密码是否与哈希值匹配,这意味着你仍然需要原始密码 哈希值以查看它们是否匹配,因此只有哈希值会让你无处可去。

$is_correct = password_verify($password_typed_by_user, $hash_gotten_from_db); // bool

归根结底,没有什么是安全的,哈希很可能会被蛮力、彩虹表或 wordlists/dictionaries 等破坏,但这无关紧要,因为它通常需要花费大量时间和努力并且可以用任何散列来完成,无论是否使用password_hash

使用更新的散列和强密码是最好的防御措施,如果用于散列密码的算法有点慢,则循环遍历单词列表并散列每个单词需要更长的时间。同样,如果密码很长或有特殊字符,则检查该长度以内的所有字符等的时间会更长

添加更多的盐没有任何作用。盐不是秘密,它只是您添加的自定义内容,以避免散列被预先计算的查找表(如彩虹表)破解。

salt 通常与散列一起存储,要么在不同字段的同一数据库中,要么在使用 PHP 的 password_hash 时,它实际上只是连接到散列,看起来像mysalt.hash.
一般来说,应该使用随机盐,这样就不可能预先生成散列表,这就是所需要的,盐不是秘密,除了使函数稍微生成散列外,它不会增加安全性独一无二,因此无法大规模复制。

这一直是个问题。希望您的用户使用的密码不在字典中或前 100 个使用的密码中。您有责任强制使用不容易在字典中找到的更强密码。

添加@adeneo 的回答,

bcrypt、pbkdf2、scrypt 和现代密码哈希策略的要点是速度慢。

是的,如果您从数据库 (SQLi) 中获得生成的哈希值,您可以尝试输入密码并尝试验证每个密码。

但是,只是尝试密码有点轻描淡写了。让我们看一些数学。

使用 bcrypt 的 password_hash() 默认成本大约需要 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 年,或之间的任何交易)。

换句话说,md5()25 GPU cluster 上每秒 可以进行大约 180,000,000,000 次猜测。要根据数据库中的百万哈希值检查那百万字典条目,大约需要 5.5 秒。

137 GPU 秒对 76,000 CPU 年。 这就是 使用 bcrypt 的原因。