考虑网站可能使用此代码来验证密码。请注意,按照建议,未指定盐。
$givenPassword = /*whatever was entered*/;
//look up $username, $encryptedPassword
if (password_verify($givenPassword, $encryptedPassword))
{
//log user in and do good things
}
假设黑客窃取了数据库并想知道“secret”是否是 $user 的密码。
$givenPassword = "secret";
//look up $username, $encryptedPassword
if (password_verify($givenPassword, $encryptedPassword))
{
//report so hacker can do evil things
}
加密代码是相同的。没有指定盐。如果我没有指定盐,但 PHP 指定了,那么为什么黑客无法使用他自己的 PHP 解释器访问相同的盐,从而使盐毫无用处?如果黑客在调用password_verify时无法访问我调用password_hash创建的盐,那么我对password_verify的调用如何访问正确的盐? 这个问题不是关于盐如何工作的,而是关于password_verify(而不是md5或其他具有程序员定义盐的旧函数)如何可以与我对password_verify的调用共享盐,而不是其他人也可以使用它。
password_verify($givenPassword, $encryptedPassword)
不能防止彩虹表攻击。此类攻击包括预先计算的
$encryptedPassword
列表,因此一旦您接触到泄露的数据库,您就可以进行简单的数据库查找,并且还可以快速检测到所有碰巧共享密码的用户。彩虹表攻击可以通过 password_hash()
来防止,它在散列之前添加随机盐,这意味着您永远不会为同一密码获得两次相同的散列:
var_dump(password_hash('1234', PASSWORD_DEFAULT));
var_dump(password_hash('1234', PASSWORD_DEFAULT));
var_dump(password_hash('1234', PASSWORD_DEFAULT));
string(60) "$2y$10$P8ZHgvrmmyyBujjrLQnvR.3iFYcrJqklGr73bckAvx3pVqkKyPj0e"
string(60) "$2y$10$UbwElT41Jwb6goz6bojEsu.I7ifKXo2yp5lYMJPlT2y8YpofkAuSy"
string(60) "$2y$10$VK5wC760UwHIaKvpMXxz5upN1AV6SH7iALsJH0wcggX.Dsg4TeUgS"
(如果你运行这段代码,你也会得到与我不同的哈希值)。
这使得预先计算的表变得无用。
password_verify($givenPassword, $encryptedPassword)
发挥的唯一作用是它
慢。
$givenPassword
需要使用原始算法和使用的盐(存储在 $encryptedPassword
中)进行哈希处理,这是通过专门设计的慢速哈希算法来完成的。这使得开始验证每个字符串组合变得不可行。要了解它有多慢,您可以更改默认选项:
$start = microtime(true);
var_dump(password_hash('1234', PASSWORD_BCRYPT, ['cost' => 17]));
$end = microtime(true);
printf("Time: %f seconds\n", $end - $start);
string(60) "$2y$17$17ZLamp.RFlZOjExzbCH0.auz2Lg5cPsZxDl9K.2oCtrR3Uxut0Y2"
Time: 5.655422 seconds
$start = microtime(true);
var_dump(password_verify('1234', '$2y$17$17ZLamp.RFlZOjExzbCH0.auz2Lg5cPsZxDl9K.2oCtrR3Uxut0Y2'));
$end = microtime(true);
printf("Time: %f seconds\n", $end - $start);
bool(true)
Time: 5.681215 seconds
函数使用随机盐生成密码的哈希值。为了能够验证密码,通常将盐和哈希值都保存在数据库中,因为您已经将它们组合在一个字符串中。 如果黑客能够获得密码的盐和哈希值的组合,那么黑客还能够验证给定的密码是否与哈希值+盐值的组合相匹配。尽管从技术上讲,这些组合可能与其他密码重叠(尽管几乎仅在理论上对于实现的算法而言),但黑客永远无法完全确定给定的输入是用户实际使用的密码,或者可能只是生成相同哈希的字符串。
虽然对于彩虹表,由于可能的组合的大小很快就会超过一定的限制,但为所有可能的密码保留这些组合并不是很实际。
您还可以考虑在处理之前向每个输入添加自定义盐,因此除了算法生成的随机盐之外,黑客还需要访问您的源代码以获取所使用的自定义盐。它不会大幅减慢黑客的速度,但至少他需要暴力破解您的 2-3 个密码,并且如果盐值不太明显的话,第一次运行时不会得到盐值。
例如
$hash = password_hash($input."mysalt");
if(password_verify($input."mysalt", $hash)){
//valid
}
谈到字典攻击,这种机制也相对安全,因为一个字符串不仅有一种可能的哈希+盐组合,而且有多种。
假设用户使用
pw123
作为密码。每次调用
password_hash()
函数时,它都会使用不同的盐。 (取决于盐的大小,这是相当大的),因此在彩虹查找表中仅保存此密码的哈希+盐将导致已经产生大量条目。