2017-07-06 58 views
0

我在本地服务器上建立了一个身份验证系统,以使用PHP和MYSQL测试运行某些脚本以供我个人使用。我跑了下面的代码,选择从“用户”表中的“用户名”和“密码”列,但我基普输入正确的凭据后收到此错误:无法选择用户名和密码用户表(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); 
    } 

?> 
+1

** WARNING **:当使用'mysqli'你应该使用[参数化查询( http://php.net/manual/en/mysqli.quickstart.prepared-statements.php)和['bind_param'](http://php.net/manual/en/mysqli-stmt.bind-param.php )将用户数据添加到您的查询。 **不要**使用手动转义和字符串插值或串联来实现此目的,因为您将创建严重的[SQL注入漏洞](http://bobby-tables.com/)。意外地未经转义的数据是一个严重的风险。使用绑定参数不那么冗长,并且更容易检查以检查您是否正确地进行了操作。 – tadman

+0

如果你使用'mysql_entities_fix_string',那么你在这里遇到了一些严重的问题,那大概是手动滚动的函数是不够的。 – tadman

+2

**警告**:编写您自己的访问控制层并不容易,并且有很多机会使其严重错误。请不要在[Laravel](http://laravel.com/)等任何现代开发框架(http://codegeekz.com/best-php-frameworks-for-developers/)上编写自己的认证系统,内置了强大的[认证系统](https://laravel.com/docs/5.4/authentication)。绝对不会遵循[推荐的安全最佳实践](http://www.phptherightway.com/#security),并且从不使用无用的弱散列(如SHA1或MD5 **)存储密码。 – tadman

回答

2

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可以验证多个参数,因此如果不需要与&&比较,则再次调用它。[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); 
    } 
} 
+0

这解决了我的问题。我发现旧代码中我错了。我用你发布的内容更新后运行脚本,现在一切正常。谢谢 – shallowGeek

相关问题