2013-10-29 66 views
10

我修改了我的舊帖子。我嘗試了crypt()函數,現在嘗試使用password_hash()和password_verify()來驗證來自數據庫的加密密碼,但在每次調用時,password_hash()函數會回退不同的加密字符串,並且password_verify()無法匹配它。使用crypt()和password_hash()函數進行加密後,密碼不匹配

這就是我如何做到這一點。

//please ignore the syntax error if any 

$data = '11'; 
$dbpass = password_hash($data, PASSWORD_BCRYPT); 
echo $dbpass; // displays the random strings on each page refresh. 

將密碼保存到數據庫後,在登錄過程中沒有得到匹配。以下是我的實際功能。

private function process_data($password){ 
    $password = __STR.$password.__STR; 
    return password_hash($password, PASSWORD_BCRYPT); 

    } 
    private function processed($login_password, $dbpassword){ 
    $login_password = __STR.$login_password.__STR; 
    return password_verify($login_password, $dbpassword); 
    } 

在爲密碼創建散列字符串的每個函數調用中,該函數下次返回不同的字符串。

+0

請仔細閱讀爲什麼你不應該使用MD5哈希密碼:http://www.php.net/manual/en/faq.passwords.php – Tchoupi

+0

我相信(在許多地方已經閱讀)是更好的做法給每個密碼自己的鹽。 – Ethan

+0

同意你的意見。我已經看到了MD5加密的反向在互聯網上很容易獲得。但是我試圖在其中添加一個鹽讓黑客很難找出這個密碼是什麼。這不是一個好主意嗎?我一直在尋找專家意見。 –

回答

44

好的,讓我們一一瀏覽。

首先,它是哈希,而不是加密。加密是雙向的,哈希是一種方式。我們想散列。我們永遠不想加密。是的,術語很重要。請使用正確的術語。

接下來,password_hash的每個調用都是假定返回不同的散列。那是因爲它產生了強烈的隨機鹽。這就是它的設計方式,以及你應該如何使用它。

此外,請勿做密碼前後加上__STR的「胡椒」事情。你什麼都不做,但可能會削弱用戶密碼(這不好)。如果你想知道爲什麼這是一個壞主意的更多信息:Read This Answer

繼續,我強烈建議您不要直接使用crypt。實際上令人驚訝的是容易搞砸併產生非常弱的哈希值。這就是爲什麼password_* api的設計。 crypt是一個低級庫,您想在代碼中使用高級庫。欲瞭解更多有關如何搞砸bcrypt的信息,請查看我的博客:Seven Ways To Screw Up Bcrypt

密碼API的設計是簡單的,一站式服務。如果它不起作用,請檢查以下內容:

  1. 您使用的是PHP> = 5.5.0嗎?或者你使用PHP> = 5.3.7與password_compat

    1. 是否數據庫列足夠寬?

      它需要至少 60個字符長。

    2. 你是否檢查該函數的結果是一個字符串,而不是bool(false)

      如果有一個內部錯誤,它會從password_hash返回一個非字符串。

    3. 您是否收到任何錯誤?

      您是否已將error_reporting設置爲其最大設置(我建議使用-1來捕捉所有內容)並檢查了代碼沒有發現任何錯誤?

    4. 你確定你使用了正確的?

      function saveUser($username, $password) { 
          $hash = password_hash($password, PASSWORD_BCRYPT); 
          // save $username and $hash to db 
      } 
      function login($username, $password) { 
          // fetch $hash from db 
          return password_verify($password, $hash); 
      } 
      

      請注意,每個應該只被調用一次。

  2. 您使用的PHP 5.3.7 <與password_compat?如果是這樣,這是你的問題。您在不受支持的PHP版本上使用兼容性庫。你可能會得到它的工作(某些RedHat發行版已經回溯了必要的修復),但是你使用的是不受支持的版本。請升級到合理的版本。

如果一切都失敗,請嘗試運行這段代碼並報告輸出:

$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG'; 
$test = crypt("password", $hash); 
$pass = $test == $hash; 

echo "Test for functionality of compat library: " . ($pass ? "Pass" : "Fail"); 
echo "\n"; 

如果返回Fail,您正在運行PHP的不受支持的版本,應該升級。如果它返回通過,那麼錯誤就在你的邏輯中(庫運行正常)。

+0

非常感謝你@ircmaxell。我嘗試了你的saveUser和登錄功能,因爲它和它的工作。現在我將在我的網站上嘗試這些,這將是最後的考驗。我不知道爲什麼它以前沒有工作。我嘗試了password_hash和password_verify函數,在使用它們之前我無法完成這項工作。希望這些不會在我的網站上工作。讓我測試,我會回到你身邊。謝謝 –

+1

它工作的人。我嘗試了你在第4點中解釋的功能。上帝保佑你。乾杯!! –

+1

@HunzaAli:很高興聽到它! – ircmaxell

1

存儲密碼的最佳方式是使用PHP的功能password_hash()。它會爲每個密碼自動生成密碼安全的鹽,並將其包含在60個字符的字符串中。你根本不用擔心鹽!

// Hash a new password for storing in the database. 
// The function automatically generates a cryptographically safe salt. 
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT); 

// Check if the hash of the entered login password, matches the stored hash. 
// The salt and the cost factor will be extracted from $existingHashFromDb. 
$isPasswordCorrect = password_verify($password, $existingHashFromDb); 

你自己的方案是非常弱的,首先你正在使用MD5這方面太快,用於生成密碼哈希值,那麼你使用靜態鹽,這違背了鹽的目的。也許你想看看我的關於safely storing passwords的教程。

編輯回答更新問題:

這是沒有必要的__STR增加密碼(如果你想添加的辣椒有更好的方式),但你的功能。例如實際上應該工作。由於隨機鹽,返回值password_hash()每次都會有所不同。這是正確的,函數password_verify()能夠提取此鹽進行驗證。在你的情況下,數據庫字段可能是問題。確保它可以容納60個字符的字符串。

+0

感謝您的幫助@martinstoeckli。在你編輯帖子之前,我想通了。實際上,我對每次獲得隨機散列字符串時間感到困惑。而且我不知道如何驗證。但我想通過''password_verify()'函數來處理這個問題。謝謝你的幫助。乾杯!! –