没有正确地重新散列

Not Rehashing Properly

我们有一个 PHP class 可以根据用户凭据读取数据库,根据需要重新哈希 SHA1 => BCrypt。效果很好,但是最近我们正在开发一个 WinForms 应用程序,并且使用 Chilkat BCrypt 程序集,我们注意到重新散列过程有奇怪的效果。

帐号class:

Username/Password 已发送。如果用户有 SHA1,则检查现有行,如果是,我们重新哈希到 BCrypt,否则我们忽略并登录(哈希验证成功)。

现在一切都很好,但是 Chilkat 使用“2a”,而我们的 classes 为最终哈希中的修订写入“2y”。这会阻止登录应用程序和网站!由于重新散列,它是其中之一(都是 bcrypt 散列,从未为我们的测试帐户找到 SHA1)。

因此,我们通过使用 public“生成器”站点生成哈希来了解情况。

我们的代码有问题吗?!

if (is_array($row))
            {
                if (password_verify($passwd, $row['password']))
                {
                    /* Check if password needs rehashing, if so then continue1 */
                    //if (password_needs_rehash(sha1($row['password']) , PASSWORD_DEFAULT))
                    if (preg_match('/^[0-9a-f]{40}$/i', $row['password'])) /* Added for App login, as both hashes are different revisions (2y => 2a) */
                    {
                        /* Rehash existing password algorithm to BCRYPT and update */
                        $newhash = password_hash($passwd, PASSWORD_BCRYPT);

                        try
                        {
                            $stmt = $pdo->prepare("UPDATE users SET password = ?, last_access = NOW(), last_login = NOW() WHERE user_id = ?");
                            $stmt->execute([$newhash, $row['user_id']]);
                        }
                        catch(PDOException $e)
                        {

                            /* If there is a PDO exception, throw a STAccountsException exception. */
                            $STe = new \STAccountsException($e);
                            $STe->setVarData(['error' => 'Rehash password failed']);
                            //$STe->setVarData(['query' => 'UPDATE users SET password = ?, last_access = NOW(), last_login = NOW() WHERE user_id = ?', 'values' => [$newhash, $row['user_id']]]);
                            throw $STe;
                        }
                    }
}

我尝试使用

更好地检测哈希
if (preg_match('/^[0-9a-f]{40}$/i', $row['password'])) {}

并且允许在网站和应用程序中登录!然而,SHA1 哈希现在从不重新哈希。这毫无意义,根据我们的数据库记录和用户反馈,这个 class 两年来从未出现过故障。

感谢任何帮助!

更新

这似乎将生成的散列中的“2y”转换为“2a”。这似乎不太合规。

PHP更新:

$hashgenerated = password_hash($passwd, PASSWORD_BCRYPT);
$newhash = str_replace('2y', '2a', mb_substr($hashgenerated, 0, 3)) . mb_substr($hashgenerated, 3);

VB.NET更新:

Dim newString As String = Replace(storedHash, "2y", "2a")

两者做同样的事情,但是 VB.NET 在读取之前动态替换散列并成功登录用户而无需任何密码修改!

一定有更好的方法。现在只是将“2y”替换为“2a”。

改为使用 VB 替换。这只是作为一个中间的“逾越节”,只是它传递了被替换的标识符。它按预期工作,并避免在 PHP 登录端更新用户密码。

Dim newString As String = Replace(storedHash, "2y", "2a")
Dim passwordValid As Boolean = crypt.BCryptVerify(password, newString)
If (passwordValid = True) Then
   MsgBox("Hash is valid")
End If