層出不窮的資料庫安全事件對多使用者會造成巨大的影響,因為人們往往習慣在不同網站使用相同的密碼,一家 “暴庫”,全部遭殃!
一般的解決方案。
1 、將明文密碼做單向 hash
$password = md5($_POST[“password”]);
2 、密碼+salt 後做單向 hash,PHP 內建了 hash() 函式,您只需要將加密方式傳給 hash() 函式就好了。您可以直接指明 sha256, sha512, md5, sha1 等加密方式
單向雜湊演演算法有一個特性,無法透過雜湊後的摘要 (digest) 恢復原始資料,常用的單向雜湊演演算法包括 SHA-256,SHA-1,MD5 等。例如,對密碼 “passwordhunter” 進 行 SHA-256 雜湊後的摘要 (digest) 如下:
“bbed833d2c7805c4bf039b140bec7e7452125a04efa9e0b296395a9b95c2d44c”
注意:攻擊者可以將所有密碼的常見組合進行單向雜湊,得到一個摘要組合,然後與資料庫中的摘要進行比對即可獲得對應的密碼。這個摘要組合也被稱為 rainbow table 。更糟糕的是,一個攻擊者只要建立上述的 rainbow table,可以匹配所有的密碼資料庫。仍然等同於一家 “暴庫”,全部遭殃。
比較好的解決方案
Bcrypt
Bcrypt 其實就是 Blowfish 和 crypt() 函式的結合,我們這裡透過 CRYPT_BLOWFISH 判斷 Blowfish 是否可用,然後像上面一樣生成一個鹽值,不過這裡需要注意的是,crypt() 的鹽值必須以 2a2a 或者 2y2y 開頭,詳細資料可以參考下面的連結:
http://www.php.net/security/crypt_blowfish.php
http://php.net/manual/en/function.crypt.php
Password Hashing API
Password Hashing API 是 PHP 5.5 之後才有的新特性,它主要是提供下面幾個函式供我們使用
password_hash() – 對密碼加密.
password_verify() – 驗證已經加密的密碼,檢驗其 hash 字串是否一致.
password_needs_rehash() – 給密碼重新加密.
password_get_info() – 返回加密演演算法的名稱和一些相關資訊.
雖然說 crypt() 函式在使用上已足夠,但是 password_hash() 不僅可以使我們的程式碼更加簡短,而且還在安全方面給了我們更好的保障,所以,現在 PHP 的官方都是推薦這種方式來加密多使用者的密碼,很多流行的框架比如 Laravel 就是用的這種加密方式
PASSWORD_DEFAULT 目前使用的就是 Bcrypt,知名的還是 Password Hashing API 。這裡需要注意的是,如果您程式碼使用的都是 PASSWORD_DEFAULT 加密方式,那麼在資料庫的表中,password 欄位就得設定超過 60 個字元長度,您也可以使用 PASSWORD_BCRYPT,這個時候,加密後字串總是 60 個字元長度。
這裡使用 password_hash() 您完全可以不提供鹽值 (salt) 和 消耗值 (cost),您可以將後者理解為一種效能的消耗值,cost 越大,加密演演算法越複雜,消耗的記憶體也就越大。當然,如果您需要指定對應的鹽值和消耗值,您可以這樣寫
custom_function_for_salt(), //write your own code to generate a suitable salt
‘cost’ => 12 // the default cost is 10
];
$hash = password_hash($password, PASSWORD_DEFAULT, $options);
echo $hash;
?>
密碼加密過後,我們需要對密碼進行驗證,以此來判斷多使用者輸入的密碼是否正確
12])) {
// cost change to 12
$hash = password_hash($password, PASSWORD_DEFAULT, [‘cost’ => 12]);
// don’t forget to store the new hash!
}
只有這樣,PHP 的 Password Hashing API 才會知道我們重現更換了加密方式,這樣的主要目的就是為了後面的密碼驗證,password_get_info(),這個函式一般可以看到下面三個資訊
algo – 演演算法例項
algoName – 演演算法名字
options – 加密時候的可選引數