2009-12-11 103 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... 
?>