2013-11-28 63 views
0

扔真的,我有一些代碼和connat圖的一個問題,爲什麼它會錯PHP/mysqli的每一次

//Searches the database for the username 
    $mysqli_username = mysqli_query($mysqli, "SELECT username FROM ajbs_users WHERE username=`".$username."`"); 
    // if name does not exist 
    if ($mysqli_username == null) 
    { 
     echo "<p>Username was inccorect, or user does not exist</p>"; 
    } 
    else //if username is correct 
    { 
     //finds and stores password of the user 
     $mysqli_userPassword = mysqli_query($mysqli, "SELECT password FROM ajbs_users WHERE password=`".$password."`"); 
     if ($mysqli_userPassword != $password) //checks password matches from user 
     { 
      echo "<p>Password was inccorrect</p>"; 
     } 
     else 
     { 
      //Login 
      echo "<p>You have been logged in"; 
      // Re directs to other page after creating a session 
     } 
    } 

腳本保持輸出「密碼不正確」的聲明。

+3

**請在使用前閱讀功能說明。它只需幾個按鍵即可:php.net/mysqli_query –

+3

'$ mysqli_userPassword'包含一個MySQL資源,**不是字符串**。你正在比較一個結果對象和一個字符串,並且比較總是評估爲'FALSE'。 –

+1

更不用說所有的徒勞掙扎 - 任何人都可以不用密碼登錄 –

回答

2

有許多與你的代碼的問題:

  • mysqli_query()不從數據庫返回的行,它返回一個資源從中你可以從數據庫中提取行。否則,如果查詢產生分析錯誤或執行錯誤,則返回false。你需要檢查這些錯誤情況。

    或者使用mysqli_report(MYSQLI_REPORT_STRICT)配置mysqli在錯誤時拋出異常(如果您知道如何編程異常)。

  • 您正在使用圍繞值$ username和$ password的back-tick。反標記用於分隔表名和列名等標識符。對於字符串值和日期值,請使用單引號。對於字符串和日期,默認情況下雙引號與單引號相同。但是如果你將MySQL設置爲ANSI模式,那麼這可能會改變,然後使用雙引號作爲標識符的反標記。請參閱MySQL's different quote marks

  • 您正在將變量直接插入到SQL表達式中,除非您非常小心地將它們轉義出來,否則這些變量不安全。這是SQL注入發生的方式。請閱讀What is SQL injection?How can I prevent SQL injection in PHP?您應該使用預準備語句並使用參數將動態元素添加到查詢中。

    請記住,如果您使用參數,報價問題將消失。你不要在參數中加任何類型的引號。 使用參數比將內容變量插入字符串更簡單也更安全。

而且一些問題,你的邏輯或應用程序設計:

  • 如果用戶名存在,你檢查。那麼如果是這樣,你檢查是否存在密碼。但在你的代碼中,的密碼不一定是由相同的用戶名使用的。您的代碼不檢查相同用戶有該密碼,只有任何用戶有該密碼。

    這是什麼意思是我可以破解你的網站,如果我可以註冊一個用戶名和密碼我知道,說'xyzzy'。然後,我可以使用密碼「xyzzy」登錄,其他用戶名爲

  • 告知用戶用戶名或密碼是否不正確不是一種好的安全措施。他們只應該被告知登錄失敗。如果他們是黑客,那麼知道他們在正確的軌道上是有用的,也就是說,他們選擇了一個有效的用戶名,他們只需要猜測密碼。您可能希望記錄信息以進行自己的故障排除,但在向用戶報告時要更加模糊。

  • 您不應該存儲明文密碼。存儲密碼的散列。還爲每個用戶存儲一個隨機salt,並在散列計算中使用它。見You're Probably Storing Passwords IncorrectlyWhat data type to use for hashed password field and what length?

  • ,如果你在一個查詢比較的用戶名和密碼,你可以這樣做搜索有一個查詢,而不是兩個。我在WHERE子句中搜索用戶名,然後將存儲的密碼哈希的布爾比較結果與用戶輸入的哈希值進行比較。

所以這裏是我如何寫它,牢記上面的所有要點。

/* 
* Search the database for the username, and report if the password matches 
*/ 
$sql = "SELECT (password = SHA2(CONCAT(?, salt), 256)) AS password_matches 
     FROM ajbs_users WHERE username = ?"; 
if (($stmt = $mysqli->prepare($sql)) === false) { 
    trigger_error($mysqli->error, E_USER_ERROR); 
} 
$stmt->bind_param("ss", $password, $username); 
if ($stmt->execute() === false) { 
    trigger_error($stmt->error, E_USER_ERROR); 
} 

$stmt->bind_result($password_matches); 
if ($stmt->fetch()) { 
    if ($password_matches) { 
     echo "<p>You have been logged in"; 
     // Re directs to other page after creating a session 
    } else { 
     error_log("Login attempted with user '$username', but password was incorrect."); 
    } 
} else { 
    error_log("Login attempted with user '$username', but user does not exist."); 
} 

// Tell the user only what they need to know. 
echo "<p>Login failed. Username or password was incorrect</p>"; 
+0

+1很好的回答!是否有任何捷徑方法使用mysqli prepare語句,仍然保持代碼簡短?你建議的任何方法? – Kevin

+1

@kevin,你仍然需要準備()和執行()作爲單獨的步驟。我更喜歡使用PDO,因爲不需要bind_param()全部。我可以將參數作爲數組參數傳遞給execute()。請參閱PDOStatement :: execute()中的示例#2。 –

+1

@kevin當然,有:https://github.com/colshrapnel/safemysql雖然數據佔位符被模擬,但它與本地一樣安全 –