2010-12-16 115 views
1

我在這裏有一些用於登錄系統的代碼,純粹是爲了學習的目的,它是由來自stackoverflow的偉大人物的一些主要幫助創建的,並且我被告知不要存儲salt和hash分離,而是一起存儲。我想知道如何在用戶嘗試登錄時比較密碼。如果鹽不存儲,我怎麼能比較這兩個。誰能幫忙?如何比較使用此代碼登錄的用戶密碼?

require("constants.php"); 
$DBH = new mysqli($dbhost, $dbuser, $dbpass, $dbname); 

function createSalt() { 
    $length = mt_rand(64, 128); 
    $salt = ''; 
    for ($i = 0; $i < $length; $i++) { 
     $salt .= chr(mt_rand(33, 255)); 
    } 
    return $salt; 
} 
//Salt function created by ircmaxell 

function registerNewUser() { 
    //Check to see if  Username Is In Use// 
    $q = $DBH->prepare("SELECT id FROM users WHERE username = ?"); 
    $username = filter_var($username, FILTER_SANITIZE_STRING); 
    $data = array($username); 
    $q->execute($data); 
    $row = $q->fetch(); 

    if ($row === false) { 
     //If Username Is Not Already In Use Insert Data// 
     $hash = hash('sha256', $pass); 
     $salt = createSalt(); 
     $hash = hash('sha256', $salt . $hash . $pass); //UPDATED 
     $data = array($username, $hash, $salt); 
     $qInsert = $DBH->prepare(
      "INSERT INTO users (username, password, salt) values (?, ?, ?)" 
     ); 
     $qInsert->execute($data); //Inserts User Data Into Table// 
    } 
} 
+0

你可以安全地跳過'$ hash = hash('sha256',$ pass);' – Jacco 2010-12-16 09:36:31

回答

2

你要查詢數據庫檢索用戶行(如果有的話),得到鹽,並使用相同的算法在由用戶提供的密碼。如果兩個哈希都匹配,則用戶提供了一個好的密碼。

做一些代碼,它將使這樣的:

$qSelect = $DBH->prepare('SELECT salt,password FROM users WHERE username = ?'); 
$qSelect->execute(); 
$qSelect->bind_result($salt, $db_password); 
$qSelect->fetch(); 

if($salt == null){ 
    // username doesn't exist 
    return; 
}  

$hash = hash('sha256', $pass); 
$hash = hash('sha256', $salt . $hash . $pass); 
if($hash == $db_password){ 
    // login ok 
} else { 
    // login nok 
} 
+0

我是否需要將salt存儲在某個地方?因爲再次運行鹽的代碼不會產生相同的結果,所以我想不出另一種重新創建哈希的方法。 – mcbeav 2010-12-16 03:49:10

+0

@mcbeav:相同的鹽和相同的密碼應**總是**產生相同的散列。 – zerkms 2010-12-16 03:49:45

+0

「我需要將鹽儲存在什麼地方嗎?」 - 你已經做到了 - 你將它存儲在'salt'字段中。 – zerkms 2010-12-16 03:50:18

2

做同樣的工作:根據用戶名

$hash = hash('sha256', $row['salt'] . hash('sha256', $pass) . $pass); 
if ($row['password'] == $hash) { 
    // the password is correct 
} 

$row已經從數據庫中獲取,而$pass是從表單中檢索密碼。

此外,它是沒有意義的包括在散列密碼兩次:散列和純文本一個

$hash = hash('sha256', $salt . $pass); // this would be enough 
+0

@zerkms:這並不是毫無意義,因爲它增加了破解密碼的複雜性。因爲你必須做兩次sha256。另外,即使短密碼也很難破解,因爲無論如何hash都是一個很長的字符串。 – RageZ 2010-12-16 03:53:27

+0

謝謝!我不知道這一點。代碼被改變爲實際上不存儲鹽,沒有看到我發佈了錯誤的代碼,但我假設我必須在這裏存儲鹽,以使事情能夠工作。是否將數據庫中的鹽儲存起來使其不那麼安全? – mcbeav 2010-12-16 03:53:51

+0

@RageZ:實際上,在這部分中,2個計算比1慢,但確實沒有更長的字符串更安全(因爲它是從相同的數據準備的)。 – zerkms 2010-12-16 03:54:39

1

問題:

1)你的用於創建哈希+鹽的密碼散列法是非傳統的。這不是嚴格的問題,它只是不是你想要的。 zerkms非常清楚地表達了這一點。

2)你的數據庫插入要求要麼用戶名是一個獨特的列,缺少一些異常處理,或者很容易受到一場比賽,這將導致多個用戶使用相同的用戶名和不同的密碼(如果是不同的ID是一個關鍵)

+0

我很抱歉,我不確定我是否完全理解你的答案。對於第二部分,你是否說過檢查用戶名是否正在使用的函數編寫不正確?如果是這樣,關於如何解決這個問題的任何想法?我是mysqli和PDO的新手,雖然這是mysqli。至於第一部分,你認爲這可能會導致任何問題?也許表演? – mcbeav 2010-12-16 04:03:40

相關問題