保護PHP密碼的哈希和鹽值

當前聽說MD5部分不安全。 考慮到這一點,我想知道使用哪一種機制進行密碼保護。 php

這個問題, 「雙重哈希」密碼是否比僅哈希一次密碼安全? 建議屢次散列多是一個好主意,而如何對單個文件實施密碼保護? 建議使用鹽。 html

我正在使用PHP。 我想要一個安全,快速的密碼加密系統。 將密碼哈希一百萬次可能更安全,但也更慢。 如何在速度和安全性之間取得良好的平衡? 另外,我但願結果具備恆定數量的字符。 前端

  1. 哈希機制必須在PHP中可用
  2. 必須安全
  3. 它可使用鹽(在這種狀況下,全部鹽都同樣好嗎?是否有任何方法能夠生成優質鹽?)

另外,我是否應該在數據庫中存儲兩個字段(例如,一個使用MD5,另外一個使用SHA)? 它會使它更安全或更不安全嗎? git

若是我不夠清楚,我想知道要使用哪一個哈希函數以及如何選擇合適的鹽,以便擁有安全,快速的密碼保護機制。 github

還沒有徹底涵蓋個人問題的相關問題: 算法

PHP中的SHA和MD5有什麼區別
簡單密碼加密
安全的asp.net密鑰,密碼存儲方法
您將如何在Tomcat 5.5中實現鹽醃密碼 shell


#1樓

我正在使用Phpass ,這是一個簡單的單文件PHP類,幾乎能夠在每一個PHP項目中輕鬆實現。 另請參見H。 數據庫

默認狀況下,它使用Phpass中實現的最強大的可用加密,該加密是bcrypt並回退到MD5等其餘加密,以向與Wordpress之類的框架提供向後兼容性。 tomcat

返回的哈希能夠原樣存儲在數據庫中。 生成哈希的示例用法是: 安全

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

要驗證密碼,可使用:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

#2樓

我只想指出,PHP 5.5包含一個密碼哈希API ,該APIcrypt()提供了包裝器。 該API大大簡化了哈希,驗證和從新哈希密碼哈希的任務。 做者還發布了一個兼容性包 (以您只require使用的單個password.php文件的形式),適用於使用PHP 5.3.7及更高版本並但願當即使用此功能的用戶。

它目前僅支持BCRYPT,可是它旨在易於擴展以包括其餘密碼哈希技術,而且因爲該技術和成本是做爲哈希的一部分存儲的,所以,對您喜歡的哈希技術/成本的更改不會使當前哈希無效將自動驗證,使用正確的技術/成本。 若是您未明肯定義本身的鹽,它還會處理生成「安全」鹽的問題。

該API公開了四個功能:

  • password_get_info() -返回有關給定哈希的信息
  • password_hash() -建立密碼哈希
  • password_needs_rehash() -檢查給定的哈希值是否與給定的選項匹配。 有用的檢查哈希是否符合您當前的技術/成本方案,容許您在必要時從新哈希
  • password_verify() -驗證密碼是否與哈希匹配

目前,這些函數接受PASSWORD_BCRYPT和PASSWORD_DEFAULT密碼常量,它們如今是同義詞,不一樣之處在於PASSWORD_DEFAULT「若是支持更新的,更強大的哈希算法,則在更新的PHP版本中可能會更改」。 在登陸時使用PASSWORD_DEFAULT和password_needs_rehash()(並在必要時進行從新哈希處理)應確保您的散列具備至關強的抵禦暴力攻擊的能力,而對您幾乎沒有任何幫助。

編輯:我剛剛意識到,這是羅伯特·K的答案中簡要提到的。 我將在這裏保留這個答案,由於我認爲它爲不瞭解安全性的人提供了更多有關其工做方式和易用性的信息。


#3樓

我在這裏找到了關於此問題的完美話題: https : //crackstation.net/hashing-security.htm ,我但願您能從中受益,這裏的源代碼也提供了針對基於時間的攻擊的防禦。

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

#4樓

儘管已經回答了問題,但我只想重申,用於哈希處理的鹽應該是隨機的,而不是像第一個答案中所建議的電子郵件地址那樣。

有關更多說明,請訪問-http : //www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

最近,我討論了用隨機位加鹽的密碼散列是否比用可猜想或已知鹽加鹽的密碼散列更安全。 讓咱們看看:若是存儲密碼的系統以及存儲隨機鹽的系統遭到破壞,則攻擊者將能夠訪問哈希和鹽,所以鹽是不是隨機的都沒有關係。 攻擊者能夠生成預先計算的彩虹表來破解哈希。 有趣的部分來了-生成預先計算的表並非那麼簡單。 讓咱們以WPA安全模型爲例。 實際上,您的WPA密碼永遠不會發送到Wireless Access Point。 而是使用您的SSID(網絡名稱,如Linksys,Dlink等)進行哈希處理。 這是一個很好的解釋。 爲了從哈希中檢索密碼,您將須要知道密碼以及鹽(網絡名稱)。 Wifi教堂已經預先計算了哈希表,該哈希表具備前1000個SSID和大約一百萬個密碼。 全部表的大小約爲40 GB。 在您的網站上能夠看到,有人使用15個FGPA陣列3天來生成這些表。 假設受害者使用的SSID爲「 a387csf3」,密碼爲「 123456」,那麼這些表會破解它嗎? 沒有! .. 這不能夠。 即便密碼很弱,表也沒有針對SSID a387csf3的哈希。 這是無鹽的美麗。 它將阻止在預計算表上蓬勃發展的餅乾用戶。 它能夠阻止堅決的黑客嗎? 可能不會。 可是使用隨機鹽確實能夠提供額外的防護層。 當咱們處於這個主題上時,讓咱們討論將隨機鹽存儲在單獨系統上的其餘優勢。 方案1:密碼哈希存儲在系統X上,用於哈希的鹽值存儲在系統Y。這些鹽值是可猜想的或已知的(例如,用戶名)方案2:密碼哈希存儲在系統X上,而且鹽值用於哈希存儲在系統Y中。這些鹽值是隨機的。 如您所料,若是系統X受到破壞,則在單獨的系統上使用隨機鹽具備巨大優點(方案2)。 攻擊者將須要猜想附加值才能破解哈希。 若是使用32位鹽,則每一個猜想的密碼將須要2 ^ 32 = 4,294,967,296(約42億)次迭代。


#5樓

謹記

關於PHP的密碼加密,已經有不少說法,其中大多數是很是好的建議,可是在您甚至開始使用PHP進行密碼加密的過程以前,請確保已實現或準備好實現如下內容。

服務器

港口

若是您沒有正確保護運行PHP和DB的服務器的安全性,那麼加密的效果如何,都將毫無用處。 大多數服務器以相對相同的方式運行,它們分配有端口,以使您能夠經過ftp或shell遠程訪問它們。 確保更改了活動的遠程鏈接的默認端口。 經過不這樣作,您實際上使攻擊者在訪問系統時少了一步。

用戶名

對於世界上全部好的東西,請勿使用用戶名admin,root或相似名稱。 另外,若是您使用的是基於UNIX的系統,請不要使root賬戶登陸名不可訪問,它應該始終僅是sudo。

密碼

您告訴用戶輸入正確的密碼以免被黑,請執行相同的操做。 後門徹底打開時,進行全部鎖定前門的努力的意義何在?

數據庫

服務器

理想狀況下,您要將數據庫和應用程序放在單獨的服務器上。 因爲成本緣由,這並不是老是可能的,可是它確實能夠保證必定的安全性,由於攻擊者必須通過兩個步驟才能徹底訪問系統。

用戶

始終讓您的應用程序擁有其本身的賬戶來訪問數據庫,並僅爲其提供所需的特權。

而後爲您提供一個單獨的用戶賬戶,該賬戶不會存儲在服務器上的任何位置,甚至不會存儲在應用程序中。

像往常同樣,不要使這個根或相似的東西。

密碼

請遵循與全部正確密碼相同的準則。 另外,請勿在同一系統上的任何SERVER或DB賬戶上重複使用相同的密碼。

的PHP

密碼

永遠不要在數據庫中存儲密碼,而要存儲哈希和惟一的鹽,稍後我將解釋緣由。

散列

單向哈希!!!!!!!,永遠不要以能夠反轉的方式哈希密碼,哈希應該是一種方式,這意味着您不要反轉並將它們與密碼進行比較,而是哈希輸入的密碼以相同的方式比較兩個哈希值。 這意味着,即便攻擊者能夠訪問數據庫,他也不知道實際的密碼是什麼,而只是密碼所產生的哈希值。 這意味着在最壞的狀況下爲用戶提供更高的安全性。

那裏有不少很好的哈希函數( password_hashhash等),可是您須要選擇一個好的算法才能使哈希有效。 (bcrypt及其相似的算法是不錯的算法。)

當散列速度是關鍵時,速度越慢越能抵抗暴力攻擊。

散列中最多見的錯誤之一是散列不是用戶獨有的。 這主要是由於不是惟一地產生鹽。

密碼在散列前應先加鹽。 Salting爲密碼添加了一個隨機字符串,所以類似的密碼在數據庫中不會顯示相同的密碼。 可是,若是鹽不是每一個用戶都惟一的鹽(即:您使用硬編碼鹽),那麼您幾乎會使鹽變得一文不值了。 由於一旦攻擊者找出了一個密碼鹽,他就對全部密碼都加鹽。

建立鹽時,請確保它與鹽鹽密碼惟一,而後將完整的哈希和鹽鹽都存儲在數據庫中。 這樣作是爲了使攻擊者必須先破解每種鹽和哈希,而後才能得到訪問權限。 對於攻擊者來講,這意味着更多的工做和時間。

用戶建立密碼

若是用戶正在經過前端建立密碼,則意味着必須將其發送到服務器。 這帶來了一個安全問題,由於這意味着未加密的密碼將發送到服務器,而且若是攻擊者可以偵聽和訪問,則您在PHP中的全部安全性都毫無用處。 老是安全地傳輸數據,這是經過SSL來完成的,可是即便SSL並不是天衣無縫,也要感到厭倦(OpenSSL的Heartbleed缺陷就是一個例子)。

還要使用戶建立一個安全的密碼,這很簡單,應該始終這樣作,最終用戶將不勝感激。

最後,不管您採起什麼安全措施都是100%安全,防禦技術越先進,攻擊就變得越先進。 可是,按照如下步驟操做將使您的站點更安全,而攻擊者則更不但願這樣作。

這是一個PHP類,可輕鬆爲密碼建立哈希和鹽

http://git.io/mSJqpw

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息