我在我的本地服务器上安装了一个身份验证系统来测试运行一些脚本供我个人使用,使用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);
}
?>
答案 0 :(得分:2)
password_verify
接受提交的密码及其关联的密码哈希,但是提供了一个布尔值($pw_temp == $row[3]
)请参阅:http://php.net/manual/en/function.password-verify.php。
假设您使用不带静态salt的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()
[sic],以避免语法冲突,但由于您的条件导致调用else
,因此isset
不需要。
&&
可以验证多个参数,因此如果不需要与SELECT * FROM `users` WHERE `username`='$un_temp' AND `password`='$pw_temp'
进行比较,则再次调用它{。{3}}。
使用标识符引号(反引号)包装列和表名称将有助于避免MySQL保留关键字问题[sic]。
password_hash
最后,由于加密算法和成本可能会在PHP安全更新[sic]之间发生变化。使用password_verify
和password_needs_rehash
时,您应始终使用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);
}
}
[sic]来确保密码仍具有加密安全性:
expect_between <- function (x, lo, hi) {
expect_lte(lo, x)
expect_lte(x, hi)
}