尝试散列密码,但每次它只是散列为 *0

Trying to hash a password, but every time it just hashes to *0

出于明显的安全原因,我正在学习如何使用 PHP 散列密码。我有以下两个函数用于设置和检查哈希值:

function password_encrypt($password)
{
    $hash_format = "y$"; //blowfish
    $salt_length = 22;
    $unique_random_string = md5(uniqid(mt_rand(), true));
    $base64_string = base64_encode($unique_random_string);
    $modified_base_64_string = str_replace('+', '.', $base64_string);
    $salt = substr($modified_base64_string, 0, $length);
    $format_and_salt = $hash_format . $salt;
    $hash = crypt($password, $format_and_salt);
    echo $hash;
    return $hash;
}

function password_check($password, $existing_hash)
{
    $hash = crypt($password, $existing_hash);
    if($hash === $existing_hash)
    {
        return true;
    }
    else
    {
        return false;
    }
}

我的问题是,每次我对密码进行哈希处理并将其发送到数据库时,它都会存储为 *0。我不知道 *0 来自哪里。我在做什么有什么问题吗?

基本上,当我使用它时,我只是从 $_POST 获取输入的密码并使用 password_encrypt() 对其进行加密。但它似乎总是以 *0 的形式出现在另一边。

简短而正确的答案

不要推出自己的密码,使用已经过安全专家审查的实施。对于 PHP 5.5 及更高版本,这意味着 password_hash()password_verify()。对于 PHP 的早期版本,您可以使用 password_compat(如果您的 PHP 版本早于 5.4,运行 不受支持的 PHP 版本会让您感到羞耻) .

Crypto Self-Education答案

如果您执意要编写自己的密码学代码(为了学习经验等),您必须保证永远不会部署未经验证的实现并使任何东西依赖于它来确保安全。否则,请使用 password_hash() and password_verify() 并立即停止阅读。


你的代码有很多问题。让我们系统地往下看,从password_encrypt()开始。 (顺便说一句,你不是在加密密码,而是在散列它。)[​​=34=]

$unique_random_string = md5(uniqid(mt_rand(), true));

是的,。这不是为 bcrypt 散列生成盐的加密安全方法。您应该看看 password_compat implements this feature. Alternatively, see how random_compat 如何为加密目的生成随机字节。 (另外,请告诉那些建议您使用该单行生成随机字符串的人,他们正在玩火。)

$unique_random_string = random_bytes(17);

继续前进...

$modified_base_64_string = str_replace('+', '.', $base64_string);
$salt = substr($modified_base64_string, 0, $length);

您在第二个变量名中忘记了下划线。此外,没有名为 $length 的变量。这些行,更正后,看起来像这样:

$modified_base_64_string = str_replace('+', '.', $base64_string);
$salt = substr($modified_base_64_string, 0, $salt_length);

接下来,

$hash = crypt($password, $format_and_salt);
echo $hash;
return $hash;

请不要在您的示例代码中留下您的 echo 语句。此外,您应该检查错误并抛出异常,这样如果 bcrypt 哈希失败,您的应用程序就不会愉快地运行。

$hash = crypt($password, $format_and_salt);
if ($hash === '*0') {
    throw new Exception('Password hashing unsuccessful.');
}
return $hash;

哇,快完成了。现在让我们看看您的 password_check() 函数:

if($hash === $existing_hash)
{
    return true;
}
else
{
    return false;
}

不要使用 ===== 比较加密输出(密码哈希、MAC 等),否则你会邀请 timing attacks into your application. Use hash_equals() for PHP 5.6, or a hash_equals() polyfill for earlier versions of PHP.

return hash_equals($hash, $existing_hash);

我希望这是一次教育经历。密码学很难,不要重新发明轮子