使用 password_verify() 验证 MD5 密码

Verifying MD5 passwords using password_verify()

有没有办法将 MD5 密码转换为 password_verify() 可以验证的密码?

我在 Crypt Wikipedia page 上看到 "The printable form of MD5 password hashes starts with $."

因此我试一试(没有任何运气):

$password = "abcd1234";
$md5hash = "$".md5($password);
var_dump(password_verify($password, $md5hash));

有什么方法可以让 password_verify() 使用 MD5 密码吗?

提问原因:我有一个旧系统,其中密码存储为 MD5 哈希。我想开始使用更安全的 Password Hashing API。如果我能够将现有的密码哈希值转换为适用于 password_verify() 的内容,我只需更新数据库条目(将 $ 添加到所有密码哈希值之前),我的程序将使用以下代码(我不必为旧的 MD5 密码做一个特例):

$password; // Provided by user when trying to log in
$hash; // Loaded from database based on username provided by user
if(password_verify($password, $hash)) {
   // The following lines will both update the MD5 passwords
   // and all passwords whenever the default hashing algorithm is updated
   if(password_needs_rehash($hash, PASSWORD_DEFAULT)) {
      $hash = password_hash($password, PASSWORD_DEFAULT);
      // Store the new hash in database
   }
   // User is logged in
} else {
   // User is not logged in
}

你不能那样做。

你可以做的是通过 password_hash() 散列 已经过 MD5 散列的 密码,并在你的数据库中为这些旧密码添加一个额外的标志,所以你知道之后对它们进行双重验证。

一些示例代码:

$passwordCompare = ($passwordIsOldFlag === true)
    ? md5($passwordInput)
    : $passwordInput;

if (password_verify($passwordCompare, $passwordHash))
{
    if ($passwordisOldFlag === true)
    {
        $passwordNewHash = password_hash($passwordInput, PASSWORD_DEFAULT);

        // Here, you'd update the database with the new, purely bcrypt hash
        // and set your passwordIsOldFlag to 0 as well
    }
}

注意:MD5 生成 32 个字符长度的字符串,而 password_hash() 最少为 60。

阅读手册:

如果您决定使用 password_hash() 或兼容包(如果 PHP < 5.5)https://github.com/ircmaxell/password_compat/,请务必注意,如果您当前的密码列的长度低于 60,则需要更改为该值(或更高值)。手册建议长度为255。

您需要更改列的长度并使用新的散列重新开始才能生效。否则,MySQL 将默默地失败。

md5(或任何其他散列算法 - 请参阅 hash_algos() 的完整列表)每次都会将某些内容散列为一个常量(相同)的东西,换句话说:

'1234' ---md5---> '81dc9bdb52d04dc20036dbd8313ed055'
'1234' ---md5---> '81dc9bdb52d04dc20036dbd8313ed055'
'1234' ---md5---> '81dc9bdb52d04dc20036dbd8313ed055'
'1234' ---md5---> '81dc9bdb52d04dc20036dbd8313ed055'
...

但是password_hash($password, $algo)每次都会将一些东西散列成新的东西,换句话说:

'1234' ---password_hash---> 'y$VXj5/N79aVolZQHJa.wdUub4C1uifXCNGRVKVUIYnsuRGs/wnXU/S'
'1234' ---password_hash---> 'y$BjSPyCyZU2Rui5MtL5MLC.bkLGbUxf/f9NshALvTc39lhemoWZFC6'
'1234' ---password_hash---> 'y$WXGX/6dCLbJN77MKNNVbCej9Fya2fQGvPjAMLuU3a6zGCDuBMisbm'
'1234' ---password_hash---> 'y$sqkB2ZK7BanIHTRZIKUHi.TVdseZE.GSMghBhuT7mDC9GrjW9g6Ky'

所以 hash_verify_kind_function() 只需要 password_hash() 生成的散列,因为你可以用 md5(或任何)散列你的字符串,然后检查它们是否相等 这是非常愚蠢的工作,因为在这种情况下你不需要先用 md5 散列它!因为实际上 md5 哈希并未用于密码哈希(以及验证)