【问题标题】:Password is not verified using function password_verify未使用函数 password_verify 验证密码
【发布时间】:2016-05-10 19:54:13
【问题描述】:

我想我已经直接从 mysql 数据库中使用函数PASSWORD 对密码进行了哈希处理(我在这里做错了吗?)。我正在尝试使用此代码验证该密码:

    if($submit)
    {
        $first=$_POST['first'];
        $password=$_POST['password'];
        $hash="*85955899FF0A8CDC2CC36745267ABA38EAD1D28"; //this is the hashed password i got by using function PASSWORD in database
        $password=password_verify($password,$hash);
        $db = new mysqli("localhost", "root","","learndb");
        $sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
        $result = $db->query($sql);
        $result=mysqli_num_rows($result);


        if($result>0)
    {

        session_start();
        $_SESSION['logged_in'] = true;
        session_regenerate_id(true);
        header("Location:loginhome.php");

    }
}

但是密码不匹配。我在这里错过了什么?

更新

在所有建议之后,我使用 php 代码中的 password_hash 存储到数据库中。

$db = new mysqli("localhost", "root","","learndb");
$password=password_hash('ChRisJoRdAn123',PASSWORD_DEFAULT);
$sql="INSERT INTO admin (username,password)values('ChrisJordan','$password')";
$db->query($sql);

密码还是不匹配。

【问题讨论】:

  • password_verify 不使用 MySQL 密码格式(它使用 Bcrypt)。
  • 你在用mysqlPASSWORD函数吗?
  • @AlexanderO'Mara 我没有在 mysql 本身中看到 Bcrypt 函数。
  • @micky 我的意思是 PHP 的 password_* 函数使用 Bcrypt,MySQL 使用其他东西。
  • @AlexanderO'Mara 请查看我有问题的更新。

标签: php mysql database mysqli passwords


【解决方案1】:

无法在数据库中搜索加盐密码哈希。要计算哈希,您需要使用您在插入语句中正确执行的 password_hash() 函数。

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);

要检查密码,您首先需要仅按用户名搜索(使用准备好的查询以避免 sql 注入):

$sql = 'select * from admin where username = ?';
$db->prepare($sql);
$db->bind_param('s', $first);

当你最终从数据库中得到存储的哈希时,可以这样检查:

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

【讨论】:

    【解决方案2】:

    password_verify 是一个布尔函数,它返回truefalse。在您的代码中,从 Post 参数获取密码值后,您执行此操作

    $password=password_verify($password,$hash);
    

    $password 的值更改为truefalse,并将该布尔值存储在您在mysql select 语句中使用的$password

    $sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
    

    另一件事是您使用的哈希/加盐密码可能不是您使用的密码的正确哈希值。


    更新:试试这个

    $cost = [
        'cost' => 15,
    ];
    
    $hash_password = password_hash('ChRisJoRdAn123', PASSWORD_BCRYPT, $cost);
    

    在任何 db 操作之前,将您的 password 字段 varchar 长度更改为 >=64

    $sql = "INSERT INTO admin (username,password)values('ChrisJordan','".$hash_password."')";
    

    插入操作后,与用户一起执行select语句

    $sql = "select * from admin where username = 'ChrisJordan'";
    

    在从 post 参数获取 hased passwordpassword 之后,您需要使用 password_verify 验证这两个密码

    if (password_verify(validate($_POST['password']), $hash_password_from_db)) {
        echo "Valid Password";
    }else{
        echo "Invalid Password";    
    }
    

    【讨论】:

    • 显示未定义的函数 validate()。
    • 你需要验证输入...我只是使用了虚拟函数。
    • @martinstoeckli 选择查询将返回用户名“ChrisJordan”的记录,在该记录中我们需要获取 hasedpassword 并在password_verify中使用相同的密码
    • @Haridarshan - 哦,对不起,我被第一条语句误导了,其中密码仍然是查询的一部分。顺便说一句,15 的成本因数可能有点高。
    • @Haridarshan - validate() 的功能是什么?它不应该在那里,password_verify() 会自行检查密码。
    【解决方案3】:

    您必须使用password_hash 对使用password_verify 验证的密码进行编码。

    MySQL 函数PASSWORD 完全不同。它用于对特定于 MySQL 身份验证的密码进行编码。 (MySQL 特别建议不要将PASSWORD 用于除 MySQL 身份验证之外的任何其他。)

    两者使用不同的哈希算法,以不同的格式呈现它们的输出,并且通常彼此不兼容。


    使用password_hashpassword_verify 的典型方式是:
    $hash = password_hash($password, PASSWORD_DEFAULT);
    //Store $hash in your database as the user's password
    
    //To verify:
    //Retrieve $hash from the database, given a username
    $valid = password_validate($password, $hash);
    

    您的代码中的问题是您正在这样做:

    $password=password_verify($password,$hash);
    $sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
    

    password_verify 返回一个布尔值(密码和哈希是否匹配)。相反,您需要从数据库中检索哈希并将输入的密码与该哈希匹配。

    【讨论】:

    • 我如何使用 mysql 中的 password_hash。我用过这个:insert into admin(username,password)values('ChrisJordan','password_hash(ChRiSjoRdaN123,PASSWORD_DEFAULT) 但失败了。你知道语法错误。
    • password_hash 是一个 PHP 函数。您必须从 PHP 代码中调用它。 MySQL 对此一无所知。
    • 现在我在 php 代码中使用了 password_hash。请查看我有问题的更新。
    【解决方案4】:

    评论太长了。

    看到此问题的任何答案旁边尚未包含绿色勾号,因此提交以下内容以指出可能的问题。

    我注意到您正试图从 MD5 转移到 password_hash() - password_verify()

    您需要知道的是,MD5 生成的字符串长度为 32 个字符,而 password_hash() 的长度为 60。

    • 使用varchar(255)

    如果您将密码列的长度保持为 32,那么您需要从该列中清除现有的哈希值,然后按照手册的建议将您的列更改为 60 或 255。

    您需要清除所有现有密码,更改您的列,创建一个新的哈希值,然后再次尝试您的登录代码。

    我在您的代码中看到了这一点:

    "*85955899FF0A8CDC2CC36745267ABA38EAD1D28"; //this is the hashed password i got by using function PASSWORD in database
    

    这个字符串*85955899FF0A8CDC2CC36745267ABA38EAD1D28有40长,太短了,被截掉了。

    这告诉我你的列的长度是 40,而不是 60,或者按照手册的建议,255。

    MD5 参考:

    将哈希值作为 32 个字符的十六进制数返回。

    password_hash()的参考:

    结果将始终为 60 个字符的字符串,如果失败则为 FALSE。

    要改变你的专栏,这里有一个参考链接:

    还要确保您的表单包含 POST 方法,并且输入具有匹配的名称属性,并且没有引入任何空格。

    您可以使用trim() 摆脱这些。

    error reporting 添加到文件顶部,这将有助于查找错误。

    <?php 
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
    
    // Then the rest of your code
    

    旁注:显示错误应该只在暂存阶段完成,而不是在生产阶段。

    还有or die(mysqli_error($db))mysqli_query()


    编辑:

    您需要做的是获取一个数组并获得匹配项。

    $sql = "select * from admin where username = '".$first."' and password = '".$password."' ";
    $result = $db->query($sql);
    
    if ($result->num_rows === 1) {
         $row = $result->fetch_array(MYSQLI_ASSOC);
            if (password_verify($password, $row['password'])) {
                //Password matches, so create the session
                // $_SESSION['user']['user_id'] = $row['user_id'];
                // header("Location:/members");
    
            echo "Match";
    
    
            }else{
                echo  "The username or password do not match";
            }
    }
    

    另一种可能的解决方案:

    $query = "SELECT * from admin WHERE username='$first'";
    
    $result = $db->query($query);
    
    if($result->num_rows ===1){
    $row = $result->fetch_array(MYSQLI_ASSOC);
    
    if (password_verify($password, $row['password'])){
    
        echo "match";
    } else {
    $error = "email or Password is invalid";
    echo $error;
    }
    
    }
    mysqli_close($db); // Closing Connection
    

    【讨论】:

    • 但我的密码列是长度为 255 个字符的 varchar,但密码仍然被截断并显示在最后。
    • @micky 看到您的其他问题stackoverflow.com/q/35156137 您正在使用TEXT,请使用VARCHAR。看看这个关于 TEXT dev.mysql.com/doc/refman/5.7/en/blob.html 如果一个 TEXT 列被索引,索引条目比较在最后用空格填充。
    • 有人建议我使用 TEXT。无论哪种方式都失败了。
    • @micky 无论哪种方式,您都可能无法将列类型从 TEXT 更改为 VARCHAR,因为这可能会产生一些不利影响,并且可能必须再次创建新的哈希值。
    • @micky 等一下,我想我知道还有什么问题。
    猜你喜欢
    • 2019-06-05
    • 2017-07-06
    • 2016-05-22
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    • 2021-05-14
    • 2020-08-25
    • 1970-01-01
    相关资源
    最近更新 更多