我正在尝试使用数据库中的密码验证用户输入的密码。我已经知道它检查用户名很好(如果用户名不存在则显示错误),但是当它尝试使用mysql密码验证密码时它永远不会工作。工作'示例'位于http://scapersclearing.com/fansite/login.php;这是PHP(注意base.php包含数据库信息和header.php,navigation.php和footer.php以及所有前端)。我计划在添加html实体并防止SQL注入一旦工作。用户名:测试 - 密码:password89(md5 c1c2434f064da663997b1a2a233bf9f6)
<?php
include("base.php"); //Include MySQL connection
$username = $_POST['username']; //Connect form username with strings
$password = $_POST['password']; //Connect form password with strings
$salt = "xia8u28jd0ajgfa"; //Define the salt string
$salt2 = "oqipoaks42duaiu"; //Define the second salt string
$password = md5($salt.$password.$salt2); //Encrypt the password
$result = mysql_query("SELECT * FROM members WHERE username = '".$username."'"); //Open the members table
while($row = mysql_fetch_array( $result )) { //Convert the members table into an array
if ( $username != $row['username'] ) { //If user entered username doesn't equal the database username
include("header.php"); //Print the message
include("navigation.php");
echo "Invalid username or password!";
include("footer.php");
}
else {
if ( $row['password'] == $password ) { //Validate username and password
setcookie('c_username', $username, time()+6000); //Set the username cookie
setcookie('c_password', $password, time()+6000); //Set the cookie
header("Location:index.php"); //Redirect to home page
} else {
include("header.php"); //Print the message
include("navigation.php");
echo "<div class=\"content\"><p>Invalid username or password!<p></div>";
include("footer.php");
} } }
?>
答案 0 :(得分:1)
以下是我的评论:
<?php
include("base.php"); //Include MySQL connection
如果'username'
或'password'
索引不存在,则以下内容将失败。使用array_key_exists()
首先测试$_POST
数组。
$username = $_POST['username'];
$password = $_POST['password'];
单一的盐就足够了,你可以通过在开始时添加一半来获得任何东西,而另一半则添加到最后。
另外:您的代码注释完全没用。不要因为发表这些明显无意义的陈述的评论而混淆你的代码。
$salt = "xia8u28jd0ajgfa"; //Define the salt string
$salt2 = "oqipoaks42duaiu"; //Define the second salt string
但是为每个用户存储不同的随机盐更安全。您可以将其存储在members
表中的数据库中。使用盐的目的是打败字典攻击。如果攻击者知道您为所有成员帐户使用单个盐,那么他可以使用您的盐从字典单词中创建一组预先计算的哈希值。
MD5()
不是一个非常强大的哈希函数。已经公布了一些危害MD5的方法。 SHA1更好,但更好的是SHA-256。 PHP中的hash()
函数支持SHA-256,但它在MySQL中作为本机函数尚不支持。
$password = md5($salt.$password.$salt2);
您的查询中存在一个广泛的SQL注入漏洞。我强烈反对“稍后修复安全漏洞”,因为对于某些查询来说,忘记执行此操作太容易了。只需预先安全的代码,然后你就不会错过任何安全。使用SQL查询参数很容易,所以不要将不安全的变量插入到查询中。
这些天真的没有理由使用过时的ext / mysql API,这是不好的做法,因为它不支持查询参数等功能。使用ext / mysqli或PDO。
$result = mysql_query("SELECT * FROM members WHERE username = '".$username."'");
while($row = mysql_fetch_array( $result )) {
如果您只查询匹配的行,为什么$username
会与$row['username']
不同?您应该测试一个空结果集,如果用户输入一个不存在的用户名会发生这种情况 - 在这种情况下,您的while()
循环将迭代零次并且以下代码永远不会运行。
if ( $username != $row['username'] ) {
include("header.php"); //Print the message
include("navigation.php");
echo "Invalid username or password!";
include("footer.php");
}
else {
. . .
我更喜欢在验证密码时运行如下所示的查询:
SELECT (password = SHA1(CONCAT(?, salt))) AS password_matches
FROM members WHERE username = ?
如果查询返回空结果集,则给出的用户名错误。如果它返回一行但password_matches
为零,那么给出的密码是错误的。当然,您不希望向用户透露哪个错误,但您可能想要了解自己的目的。例如,应该锁定接收许多失败登录尝试的给定帐户。
如果你想使用SHA-256,你必须获取用户的盐,然后在PHP代码中使用hash()
:
$stmt = $pdo->prepare("SELECT salt FROM members WHERE username = ?");
$stmt->execute( array($username) );
$rows = $stmt->fetchAll();
if (count($rows) > 0) {
$password_hash = hash('sha256', $password . $rows[0]['salt']);
$stmt = $pdo->prepare("SELECT password=? AS password_matches
FROM members WHERE username = ?");
$stmt->execute( array($password_hash, $username) );
$rows = $stmt->fetchAll();
if ($rows[0]['password_matches'] > 0) {
// username and password are correct
} else {
// password was wrong
}
} else {
// username was not found
}
答案 1 :(得分:0)
一些评论/建议:
您的表格中没有任何重复的用户,是吗?这会导致您描述的问题:第一行返回false,输出被发送到浏览器,并且不能再发送标题,尽管后面的行可能有效。
所以我认为你需要简化你的代码,如果之后还有错误,那么它们将更容易找到。
答案 2 :(得分:0)
首先确保您生成的哈希值与注册时在数据库中插入的哈希值相同。
然后,您应该验证用户的方式是:
$res = mysql_query("SELECT just,the,needed,info FROM `members` WHERE `username` = '". esc($user) ."' AND `password` = '". esc($pass) ."'");
if ($hlp = mysql_fetch_assoc($res))
echo 'ok';
else
echo 'invalid username or password';
其中esc()是您的最爱。转义函数(mysql_escape_string或mysql_real_escape_string)。
现在在数据库中检查密码的有效性,所以你永远不会得到真正的哈希值。
答案 3 :(得分:0)
PHP有一个crypt函数,非常适合这种事情。 www.php.net/crypt
它会自动生成随机盐并将其与密码一起存储,使其非常易于使用。请看下面的代码。
将这个答案与其他有关准备好的陈述的答案相结合,你将成为金色。
这就是你要做的事情(我正在删除大量代码,并采用捷径,这样你就可以获得必需品):
<?php
# to register:
query('INSERT INTO users (user, pass) VALUES (?, ?)', array($user, crypt($pass)));
# to verify:
$urow = query('SELECT user, pass FROM users WHERE user = ?', array($user));
if (rows() < 1) {
die('No such user');
}
else if (crypt($pass, $urow['pass']) != $urow['pass']) {
die('Wrong password!');
}
#once you're here, it passed, and so on...
?>