在@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种密码组合。由于每个哈希值都附带一个盐值,攻击者需要对每个泄漏的哈希值都重复尝试这些密码组合。
如果你的数据库中有1,000,000个用户,则尝试将字典中的密码与数据库中的密码进行匹配将需要76,000个CPU年(其中一个CPU使用76,000年,或者76,000个CPU使用1年,或者任何其他组合)。
更具体地说,md5()
在一台25个GPU的计算机集群上可以每秒执行约1800亿次哈希验证。要对来自数据库的1,000,000个哈希值进行一百万个字典条目的验证,大约需要5.5秒钟。
137个GPU秒与76,000个CPU年相比。这就是为什么使用bcrypt的原因。
password_verify
来检查猜测的密码是否等于哈希值吗?- 在哈希之前添加额外的盐会改善它吗? - Khalid Al-Mutawa