為什麼密碼要經過雜湊?
一個安全的網頁資料庫應該儲存的是「 經過雜湊的密碼 」而不是使用者輸入時的明碼,這也是為什麼「 按下忘記密碼的按鈕,通常會導到重設密碼、而不是給你原先的密碼,因為資料庫也找不到原碼。」
所以由此推斷出,要是你在某網站按了忘記密碼,系統卻寄了一封「 你原本的密碼 」的 mail,請小心這代表此網站存的是明碼!
存明碼的風險是什麼? 代表此網站的資料庫要是被盜,密碼就被偷走了,所以現代網頁開發應該至少都要做到資料庫被偷,也不至於讓最重要的密碼被拿走或猜出來。
而讓密碼換一層皮的就稱為雜湊
。這邊是個大家容易搞混的地方,要注意這步驟、不會稱為加密
。
雜湊、加密?
雖然目的同樣是讓密碼看起來像亂碼,但兩者最重要的差別就在於:「 加密可逆、雜湊不可密 」
雜湊:單向生成,無法反推出原來的原碼
- 將不定長度 (無窮可能) 訊息的輸入,演算成 固定長度 雜湊值的輸出,即輸出的長度不受原文長度影響。
- 同樣的輸入 -> 一定是同樣的輸出
- 但因為長度是有限的,所以不同輸入也「 可能有同樣的輸出 」,雖然機率非常低,而如有這種情況、又稱為「 碰撞 」Collision。
- 為了防止被攻擊破解,通常會再加鹽 (salt),指的是再加入一組亂數(有可能是以當下時間為基底的亂數),這樣就算破解了也難以知道原碼,除非連加入亂數的方式也被破解。
- 常見的雜湊演算法:
- MD5 ( 已被證實不安全 )
- SHA-1 ( 已被證實不安全 )
- SHA-256
- 比 md5 還強、安全性更高的雜湊函數,但對於伺服器來說,越安全、也代表速度越慢
最常見的攻擊方法:
- 窮舉法又稱暴力破解 ( brute-force )
- 就是將所有可能的數列組合都丟進去跑。
- 長度要是超過一定程度、運算時間會倍增,每增加一字元,密碼組合數量會以數十倍來指數成長。
- 字典法 ( Dictionary Attacke )
- 嘗試所有「 常見的密碼 」或使用者的身份資料(親人姓名,電話,出生月日)當作字典資料庫,尤其是出現頻率的密碼組合,例如: password, mypassword, abc123, 1234567… 等等
- 效率要比窮舉法好得多,特別是資安概念不佳的使用者,但對於密碼無規律者沒效。
- 彩虹表 ( rainbow table )
- 指的是把所有可能的輸入都丟進雜湊函數,額外產生一張 hash值 輸出列表,所以本質上也算是一種暴力攻擊法。
加密:拿到密鑰的方式就可以逆推回去
- 需要密鑰,且可以透過解密得到原文。
- 分為「 對稱式 」、「 非對稱式 」
- 對稱式加密:
- 常見演算法: DES, 3DES, AES
- 密鑰要是太簡單或長度太短,安全性以及在實際應用上不夠理想,所以出現安全性更高,應用範圍更廣的非對稱式加密(Asymmetric Encryption)。
- 非對稱式加密:
- 常見演算法: RSA, DSA, ECC
- 演算法會有兩把鑰匙,一把稱做公鑰(可以公開),另一把稱做私鑰(自己要藏好)。
- 可以生成數位簽章,確認密文的傳送方身份真的是本人
PHP 內建雜湊函式 password_hash
(PHP 5 >= 5.5.0, PHP 7)
使用 password hash() 可以直接用最簡單的方式實踐複雜的加密,在使用時,需要搭配第二個參數,推薦直接使用 PASSWORD_DEFAULT
每次處理時,都會在背後產生隨機的 SALT。
當然,也可以手動指定要使用哪一個 SALT,但最好不要,就交給 PASSWORD_DEFAULT 來隨機處理,會更加安全
<?php
$hash = password_hash('your_password', PASSWORD_DEFAULT);
?>
另外也可以搭配第三個 cost 參數 (默認為 10),當值調整越大,所需耗費的計算時間就會越多,可以自行測試。
<?php
$password = '123456'; // 原始密碼
$hash_password = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($password , $hash_password)){
echo "密碼正確";
}else{
echo "密碼錯誤";
}
?>