【问题标题】:Can't Select username and password Column from user table (MySql)无法从用户表中选择用户名和密码列(MySql)
【发布时间】:2017-07-06 09:04:55
【问题描述】:

我正在本地服务器上建立一个身份验证系统,以测试运行一些使用 PHP 和 MYSQL 供我个人使用的脚本。我运行以下代码从“用户”表中选择“用户名”和“密码”列,但在输入正确的凭据后我会收到此错误:

Invalid username/password combination

这是脚本:

<?php // authentication.php 

require_once 'login.php';

$connection = new mysqli($hn, $un, $pw, $db);
if ($connection->connect_error) die($connection->connect_error);


if (isset($_SERVER['PHP_AUTH_USER']) &&
     isset($_SERVER['PHP_AUTH_PW'])) {

        $un_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_USER']);
        $pw_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_PW']);

        $query = "SELECT * FROM users WHERE username='$un_temp' AND password='$pw_temp'";
        $result = $connection->query($query);
        if (!$result) die($connection->error);

    else if ($result->num_rows) {

        $row = $result->fetch_array(MYSQLI_NUM);
        $result->close();


            if ( password_verify( $pw_temp == $row[3]) ) {

                echo "$row[0] $row[1] : Hi $row[0], you are now logged in as '$row[2]'";

            }

        }

            else die("Invalid username/password combination");

     } else {

            header('WWW-Authenticate: Basic realm="Restricted Section"');
            header('HTTP/1.0 401 Unauthorized');
            die("Pleaser enter your username and password");
     }

    $connection->close();

    function mysql_entities_fix_string($connection, $string) {

        return htmlentities(mysql_fix_string($connection, $string));
     }

    function mysql_fix_string($connection, $string) {

        if (get_magic_quotes_gpc()) $string = stripslashes($string);
        return $connection->real_escape_string($string);
     }

?>

【问题讨论】:

  • 警告:使用mysqli 时,您应该使用parameterized queriesbind_param 将用户数据添加到您的查询中。 请勿使用手动转义和字符串插值或连接来完成此操作,因为您将创建严重的SQL injection bugs。意外未转义的数据是一个严重的风险。使用绑定参数不那么冗长,并且更容易检查以检查您是否正确执行。
  • 警告:编写自己的访问控制层并不容易,而且有很多机会会严重错误。当任何现代的development framework(如Laravel)带有强大的authentication system 内置时,请不要编写自己的身份验证系统。至少遵循 recommended security best practices 并且永远不要使用 SHA1 或 MD5 等无用的弱哈希存储密码
  • @doug 感谢您的反馈。问题是几年前我发起了一场针对mysql_query 的单人运动,它已经发展成为一种运动,提醒新编码人员注意SQL 注入错误、过时API 等的风险。这是更进一步的一步。在这个时代,使用 MD5 或类似的快速哈希作为密码是不可接受的。编写自己的登录代码总是很麻烦,即使对于有经验的程序员来说,也有很多事情可能会出错。在大多数情况下,框架已经从这些东西的丑陋方面涵盖了您。
  • 这里的问题是令牌值与您期望的不匹配,但是当您编写自己的超级古怪的密码哈希算法时,您基本上必须弄清楚如果您希望该特定方法起作用,则为您自己。如果您将其替换为password_hashpassword_verify,则不会出现此问题,并且您的密码实际上会以安全的方式存储。
  • @tadman 感谢您的观察。密码的哈希值确实被截断了。我使用 password_verify() 验证了它。

标签: php mysql


【解决方案1】:

password_verify 接受提交的密码及其关联的密码哈希,但提供了一个布尔值 ($pw_temp == $row[3]) 请参阅:http://php.net/manual/en/function.password-verify.php

假设您使用不带静态盐的password_hash 将值保存在数据库中。无法查询密码列,因为password_hash 将自动使用唯一值加盐密码。这会阻止您将提交值的第二个哈希值与数据库中的哈希值进行比较。因此,您要么需要将用户名存储为唯一索引,要么遍历重复的用户名,然后调用 password_verify 来比较每个用户的密码。

假设用户名在您的表中是唯一的,您应该将代码更新为如下所示。

if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
    header('WWW-Authenticate: Basic realm="Restricted Section"');
    header('HTTP/1.0 401 Unauthorized');
    die("Please enter your username and password");
}
$un_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_USER']);
$pw_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_PW']);
$query = "SELECT * FROM `users` WHERE `username`='$un_temp'";
if (!$result = $connection->query($query)) {
    die($connection->error);
}
if (!$result->num_rows) {
    die("Invalid username/password combination");
}
$row = $result->fetch_array(MYSQLI_NUM);
$result->close();
if (password_verify($pw_temp, $row[3])) {
    echo "$row[0] $row[1] : Hi $row[0], you are now logged in as '$row[2]'";
}
$connection->close();

Demonstration 注意每个散列密码的不同之处。 请记住,由于我无法查询数据库,因此我使用数组来显示等效过程。


您的原始代码中还存在一些与语法相关的问题,在评论中需要注意。

else if 应该是一个单词,以便它看起来像 elseif [sic] 以避免语法冲突,但由于您的条件导致调用 die(),因此不需要 else

isset 可以验证多个参数,因此如果不需要与&amp;&amp; 比较[sic],则再次调用它。

使用标识符引号(反引号)包装列名和表名,将有助于避免 MySQL 保留关键字问题[sic]

SELECT * FROM `users` WHERE `username`='$un_temp' AND `password`='$pw_temp'

最后,由于加密算法和费用在 PHP 安全更新[sic] 之间会发生变化。使用password_hashpassword_verify 时,您应该始终确保密码仍然是加密安全的,使用password_needs_rehash [sic] 如下:

if (password_verify($password, $oldHash)) {
    //verify legacy password to new password_hash options
    if (password_needs_rehash($oldHash, \PASSWORD_DEFAULT)) {
        //rehash/store plain-text password using new hash
        $newHash = password_hash($password, \PASSWORD_DEFAULT);
        $updateSQL = "UPDATE `users` SET `password`='$newHash' WHERE `username`='$un_temp' AND `password`='$oldHash'";
        $connection->query($updateSQL);
    }
}

【讨论】:

  • 这解决了我的问题。我检测到我在旧代码中的错误所在。我在用您发布的内容更新脚本后运行了脚本,现在一切都很好。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多