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