2009-12-11 82 views
0

我想验证用户输入的密码与数据库中的密码。我已经知道它会检查用户名是否正确(如果用户名不存在,它会显示错误),但是当它尝试使用mysql密码验证密码时,它永远不会工作。工作'例子'在http://scapersclearing.com/fansite/login.php;这是PHP(注意base.php包含数据库信息和header.php,navigation.php和footer.php以及所有的前端)。我正计划添加html实体,并在此工作后阻止SQL注入。用户名:测试 - 密码:password89(MD5 c1c2434f064da663997b1a2a233bf9f6)数据库“验证”PHP

<?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"); 
} } } 
?> 
+1

有它呼应了哈希数据库以及脚本创建的散列,以查看它们是否匹配。 – 2009-12-11 02:20:42

+2

使用'SELECT * FROM MEMBERS WHERE username =?和password =?' - 如果返回一行,则密码正确,否则不正确。你的数据库没有验证密码 - 在你的例子中逻辑完全是PHP。 – 2009-12-11 02:23:21

+0

另外,在将用户名直接传递到查询中时,您有一个巨大的潜在SQL注入漏洞。改用PDO。 – benjy 2009-12-11 02:27:39

回答

0

一些评论/建议:

  • 你应该检查你的DATEBASE有效的用户名/密码组合,具体哪一行应退还在成功的情况下,有效用户名的while循环只能在用户名不唯一时导致错误(我想他们应该是,但这取决于你),并且找到的第一行与你的密码不匹配。

表中没有任何重复的用户,有吗?这会导致你描述的问题:第一行返回false,输出发送到浏览器,头不能再发送,尽管后面的一行可能是有效的。

  • 你的第一个if语句是没有意义的,你已经选择了所有行$用户名= = $行[“用户名”]所以你基本上是测试1!= 1

所以我认为你需要简化你的代码,如果之后还有错误,他们会更容易找到。

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)。

现在在数据库中检查密码的有效性,所以你永远不会得到真正的散列。

1

这里是我的意见:如果不存在'username''password'指标

<?php 
include("base.php"); //Include MySQL connection 

下面将失败。首先使用array_key_exists()来测试$_POST阵列。

$username = $_POST['username']; 
$password = $_POST['password']; 

单盐是足够的,你没有得到任何收益,其中一半增加到开始和另一半到最后。

此外:您的代码评论是完全无用的。不要费心使用那些做出如此明显而不含言的声明的评论来混淆你的代码。

$salt = "xia8u28jd0ajgfa"; //Define the salt string 
$salt2 = "oqipoaks42duaiu"; //Define the second salt string 

但它是更安全的存储每个用户不同随机盐。您可以将其存储在数据库中的members表中。使用盐的目的是击败字典攻击。如果攻击者知道您为所有成员帐户使用salt,那么他可以使用salt从字典单词中创建一组预先计算的哈希值。

MD5()不是一个非常强大的散列函数。一些破坏MD5的方法已经发布。更好的是SHA1,但更好的是SHA-256。在PHP中,SHA-256受hash()函数的支持,但它作为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 
} 
0

PHP有半地穴式的功能,非常适合这种事情。 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... 
?>