在未指定salt的情况下,PHP 8的password_verify如何防止彩虹表攻击? [重复]

问题描述 投票:0回答:2

考虑网站可能使用此代码来验证密码。请注意,按照建议,未指定盐。

$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的调用共享盐,而不是其他人也可以使用它。

php encryption
2个回答
1
投票
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


-1
投票
password_hash()

函数使用随机盐生成密码的哈希值。为了能够验证密码,通常将盐和哈希值都保存在数据库中,因为您已经将它们组合在一个字符串中。 如果黑客能够获得密码的盐和哈希值的组合,那么黑客还能够验证给定的密码是否与哈希值+盐值的组合相匹配。尽管从技术上讲,这些组合可能与其他密码重叠(尽管几乎仅在理论上对于实现的算法而言),但黑客永远无法完全确定给定的输入是用户实际使用的密码,或者可能只是生成相同哈希的字符串。

虽然对于彩虹表,由于可能的组合的大小很快就会超过一定的限制,但为所有可能的密码保留这些组合并不是很实际。

您还可以考虑在处理之前向每个输入添加自定义盐,因此除了算法生成的随机盐之外,黑客还需要访问您的源代码以获取所使用的自定义盐。它不会大幅减慢黑客的速度,但至少他需要暴力破解您的 2-3 个密码,并且如果盐值不太明显的话,第一次运行时不会得到盐值。

例如

$hash = password_hash($input."mysalt"); if(password_verify($input."mysalt", $hash)){ //valid }

谈到字典攻击,这种机制也相对安全,因为一个字符串不仅有一种可能的哈希+盐组合,而且有多种。

假设用户使用

pw123

作为密码。每次调用

password_hash()
函数时,它都会使用不同的盐。 (取决于盐的大小,这是相当大的),因此在彩虹查找表中仅保存此密码的哈希+盐将导致已经产生大量条目。
    

© www.soinside.com 2019 - 2024. All rights reserved.