数据库“验证”PHP

时间:2009-12-11 02:13:03

标签: php database validation forms

我正在尝试使用数据库中的密码验证用户输入的密码。我已经知道它检查用户名很好(如果用户名不存在则显示错误),但是当它尝试使用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");
} } }
?>

4 个答案:

答案 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)

一些评论/建议:

  • 你应该在你的数据库中检查一个有效的用户名/密码组合,并且在成功的情况下应该返回一行,有效用户名的while循环只会在用户名不唯一时导致错误(我想他们应该是的,但这取决于你),找到的第一行与你的密码不符。

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

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

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

答案 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...
?>