首页 > 解决方案 > 即使硬编码,PHP password_verify 也总是返回 false

问题描述

这是我的代码:

function login() {
    //Declare variables
    $username = $_POST["login"]; 
    $password = $_POST["password"];
    $client = $_POST["clients"];

    //QueryDB
    $servername = "localhost";
    $SQLUsername = "XXXX";
    $SQLPassword = "XXXX";
    $dbname = "XXXX";

    $conn = new mysqli($servername, $SQLUsername, $SQLPassword, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    //Set query then run it
    $sql = "SELECT * FROM Users WHERE Username ='$username'";
    $result = $conn->query($sql);
    $row = $result->fetch_array(MYSQLI_ASSOC);

    //Verify Password
     if ($result->num_rows === 1) {
        if (password_verify($password, $row['Password'])) {
            //Build XML request
            $XMLRequest = "<?xml version='1.0'?><Login><Client>".$client."</Client><LoginDetails><Username>".$username."</Username><Password>".$newhash."</Password></LoginDetails></Login>";

            //Build URL
            $ReplacedValues = array("NewType" => "login", "NewHash" => $XMLRequest);
            $NewString = strtr($GLOBALS["params"], $ReplacedValues);

            $NewUrl = $GLOBALS["link"].$NewString;

            //Post to Server
            header('Location: '.$NewUrl);
        }
        else {
            echo "Password is wrong"."<br>";
            echo $password."<br>";
            echo $row['Password'];
        }
    } else {
        echo "more then 1 row";
    }

    mysqli_close($conn);
}

我的问题是,即使我将密码变量和哈希变量硬编码为它们各自的值,if 条件也会返回 false。知道为什么吗?该页面在加载时会加载 else 条件以向我显示用户输入密码和来自数据库的正确哈希值。我的数据库设置为 CHAR(255) 作为密码。

更新** 这是我在评论中讨论的 C#。这不是数据库插入语句部分的完整代码。我能够很好地插入 SQL 服务器数据库。

public static string WebsiteRegister(XmlDocument XMLBody)
        {
            //Get SQL connection string
            XmlNodeList XMLNodes = SQLConnectionMethods.EstablishSQLServerConnection("SQL");
            string ConnectionString = XMLNodes.Item(0).ChildNodes[0].InnerText;
            string UserName = XMLNodes.Item(0).ChildNodes[1].InnerText;
            string Password = XMLNodes.Item(0).ChildNodes[2].InnerText;

            //Open connnection
            SqlConnection cnn = new SqlConnection(ConnectionString);
            SQLConnectionMethods.OpenSQLServerConnection(cnn);

            try
            {
                string username = XMLBody.SelectSingleNode("register/registerdetails/username").InnerText;
                string pass = XMLBody.SelectSingleNode("register/registerdetails/password").InnerText;
                string fname = XMLBody.SelectSingleNode("register/registerdetails/firstname").InnerText;
                string lname = XMLBody.SelectSingleNode("register/registerdetails/lastname").InnerText;
                string email = XMLBody.SelectSingleNode("register/registerdetails/email").InnerText;
                string accountRef = XMLBody.SelectSingleNode("register/registerdetails/accountreference").InnerText;
                string client = XMLBody.SelectSingleNode("register/client").InnerText;

                //Build Query string
                string queryString = $"Insert into [dbo].[UserAccounts] (AccountReference, FirstName, LastName, Email, Username, Pass, Client) values ('{accountRef}', '{fname}', '{lname}', '{email}', '{username}', '{pass}', '{client}')";

                //Process request
                using (SqlCommand myCommand = new SqlCommand(queryString, cnn))
                {
                    string Result = (string)myCommand.ExecuteScalar();

标签: phppasswords

解决方案


我在这里找不到您的代码中的任何问题,但是由于哈希和验证是一个取决于许多因素的成功过程,因此我想给您一些提示,以便您可以自己检查是否存在任何潜在问题。

  1. 确保在散列密码之前没有转义/清理密码。这样您就可以更改存储的密码。让

    $password = $_POST['密码'];

在您创建帐户时以及在登录时检查密码是否匹配时。

  1. 确保你用单引号 (') 而不是双引号 (") 括住哈希变量。使用双引号使 PHP 读取每个带有 "$" 的配对字符作为独立变量,这可能会导致你的代码中断,使用单引号反而。

  2. 确保数据库中的密码字段(存储散列密码)最多可以存储 255 个字符。根据文档,建议将结果存储在可以扩展超过 60 个字符的数据库列中(255 个字符是一个不错的选择)。如果该字段较窄,则哈希将被截断,您将永远不会有匹配项。

  3. 当您在登录时通过用户名获取用户时,请确保用户名是唯一的,只要它是您的主键(在表定义中)。在用户注册和登录时(在 php 级别)也检查这一点是个好主意。

  4. 回显哈希和输入的值,并确保它们与在 password_hash() 期间插入和生成的值匹配 如果数据库值不同(哈希),请确保其列的类型是 varchar(256),哈希通常是60 个字符长,但散列函数经常被改进,因此将来可能会扩大长度。

  5. 如果输入的值不同(用户密码),请确保过滤不会破坏密码值。

  6. 还要检查另一个变量是否与您存储密码的变量同名。

  7. 如果password_verify($password, password_hash($password, PASSWORD_DEFAULT)) “有效”,那么问题在于 $row['Password'] 不包含预期的内容 - 包括未正确生成。

  8. 如果它“不起作用”,那么另一条线会导致观察到的行为。这两种结果都允许专注于精炼的问题集。

  9. 尝试从匹配的另一列更改密码并将其复制到您的密码列并输入该密码进行检查。如果它有效,那么您存储的密码有问题

  10. 尝试将此哈希复制到您的密码列

    $2y$10$uDnEpQpkh9RO5tWwOrHtneLAuYMRDstRaKGZFyHubObDR0789OMO6

这是使用 bycrypt 的 123456 的散列密码。选择此密码并尝试在从 sql 中选择此密码后使用 password_verify(123456,$yourhashedfromdatabase) 进行验证,如果它有效,那么在输入数据并进入数据库后可能会有一些操作。它不会检查到达数据库的密码是否与您通过回显输入的密码完全相同。

更新: 更新代码后,我看到在输入密码时使用“Pass”列,但在提取时使用“Password”列。这可能是问题


推荐阅读