【问题标题】:Convert old md5 passwords to password_hash将旧的 md5 密码转换为 password_hash
【发布时间】:2019-06-08 08:05:21
【问题描述】:

在 php 站点上将旧的 md5 密码更新为 password_hash 时遇到问题 我能够将所有文件更新为 password_hash 我只是在会员下次登录时更新数据库中的旧密码

这里是原代码

    $password = passhash($_POST["password"]);

    if (!empty($_POST["username"]) && !empty($_POST["password"])) {
        $res = SQL_Query_exec("SELECT id, password, secret, status, enabled FROM users WHERE username = " . sqlesc($_POST["username"]) . "");
        $row = mysqli_fetch_assoc($res);

        if ( ! $row || $row["password"] != $password )
            $message = T_("LOGIN_INCORRECT");
        elseif ($row["status"] == "pending")
            $message = T_("ACCOUNT_PENDING");
        elseif ($row["enabled"] == "no")
            $message = T_("ACCOUNT_DISABLED");
    } else
        $message = T_("NO_EMPTY_FIELDS");

这里有密码哈希

    $password = $_POST["password"];

    if (!empty($_POST["username"]) && !empty($_POST["password"])) {
        $res = SQL_Query_exec("SELECT id, password, secret, status, enabled FROM users WHERE username = " . sqlesc($_POST["username"]) . "");
        $row = mysqli_fetch_assoc($res);

        if ( !$row || !password_verify($password,$row["password"]))
            $message = T_("LOGIN_INCORRECT");
        elseif ($row["status"] == "pending")
            $message = T_("ACCOUNT_PENDING");
        elseif ($row["enabled"] == "no")
            $message = T_("ACCOUNT_DISABLED");
    } else
        $message = T_("NO_EMPTY_FIELDS");

我认为它应该是这样的,但似乎无法在验证行之前让它工作

   if (strlen($password) > 40)
   {
   // Password already converted, verify using password_verify
   } else {

// User still using the old MD5, update it!
    if ($password = passhash($_POST["password"]))
    {
    // update to password_hash
    SQL_Query_exec("UPDATE users SET password WHERE username = " . 
    sqlesc($_POST["username"]) . "");
    }
}

【问题讨论】:

  • 您的查询 UPDATE users SET password WHERE username = .... 实际上并没有更新任何内容。

标签: php md5


【解决方案1】:

我建议您暂时将旧的password 保留在数据库中,并在其旁边创建一个名称更合适的新passwordHash。这样一来,您就可以随时退回到旧的做事方式,以防万一您犯了错误。

当用户登录时,您确实可以访问未散列的密码。此时您可以创建new hash

$password = $_POST["password"];
$passwordHash = password_hash($password, PASSWORD_DEFAULT);

之后你需要实际存储新的哈希:

SQL_Query_exec("UPDATE users 
                SET passwordHash = " . sqlesc($passwordHash) . "
                WHERE username = " . sqlesc($_POST["username"]));

然后,使用新哈希只是检查新哈希是否存在的问题。如果不是,则创建它,否则使用它。

一段时间后,当您知道新散列可靠地工作时,您可以从数据库中为拥有新散列的用户删除旧的 MD5 散列(在进行备份之后!)。

注意:您正在转义用户输入,而不是使用准备好的语句。那不是最好的选择。见:How to Prevent SQL Injection Vulnerabilities in PHP Applications 上面写着:

不要通过转义或删除特殊字符来清理用户输入。 攻击者可以使用编码绕过这种保护。

或查看the PHP manual itself 的内容:

对绑定变量使用准备好的语句。

【讨论】:

    【解决方案2】:

    在最后一个示例中,您似乎正在检查输入密码的长度,而不是哈希密码。您需要先从数据库中获取密码

    if (!empty($_POST["username"]) && !empty($_POST["password"]))
    {
        $password = $_POST["password"];
        $res = SQL_Query_exec("SELECT id, password, secret, status, enabled FROM users WHERE username = " . sqlesc($_POST["username"]) . "");
        $row = mysqli_fetch_assoc($res);
        if(strlen($row["password"]) == 40) // New hash
        {
            if ( !$row || !password_verify($password,$row["password"]))
                $message = T_("LOGIN_INCORRECT");
            elseif ($row["status"] == "pending")
                $message = T_("ACCOUNT_PENDING");
            elseif ($row["enabled"] == "no")
                $message = T_("ACCOUNT_DISABLED");
        }
        else                                // Old hash
        {
            $doUpdate = 1;
            $oldhash = passhash($password);
            if ( ! $row || $row["password"] != $oldhash )
            {
                $doUpdate = 0;
                $message = T_("LOGIN_INCORRECT");
            }
            elseif ($row["status"] == "pending")
                $message = T_("ACCOUNT_PENDING");
            elseif ($row["enabled"] == "no")
                $message = T_("ACCOUNT_DISABLED");
            if($doUpdate == 1) // Assuming all went well
                    SQL_Query_exec("UPDATE users SET password = '" . newpasshashfunction($password) . "' WHERE username = " . sqlesc($_POST["username"]) . "");
        }
    }
    else
        $message = T_("NO_EMPTY_FIELDS");
    

    这段代码可以清理不少

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-02
      • 2020-12-26
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-06
      • 2017-04-29
      相关资源
      最近更新 更多