敏感資料的儲存一直以來都是個問題,儲存的資料又分為只需要驗證是否一致(hash)或是需要可以反解回來(crypto),前者對應的通常是使用者的密碼,只需要驗證輸入是否一致即可。後者比較像是使用者的身分證字號或是信用卡卡號之類的。
關於密碼,以前常見的儲存方式會是使用雜湊來儲存,譬如說:
SHA1(password) = hash
透過這樣的方式儲存,可以在不知道使用者的密碼的情況下驗證密碼的正確性,假設資料庫儲存的密碼真的洩漏出去了,也沒辦法反推原始的密碼,感覺起來很完美!
但是如果你看到 7c222fb2927d828af22f592134e8932480637c0d 然後再去 Google 搜尋,你就會發現他其實是 12345678 的 SHA1 結果
SHA1(12345678) = 7c222fb2927d828af22f592134e8932480637c0d
為了避免這個問題,後來就推出了新的金鑰雜湊訊息鑑別碼(HMAC)的方式,透過一把私鑰(key)混入雜湊讓同樣的密碼會產生出不一樣的 hash 值
HMAC(password, key) = hash
在私鑰(key)沒有被揭露的前提下,提高了破解的難度,但是如果私鑰也被洩漏了的話,保護效果就沒有想像中的好了。
現在很安全的 SHA512 可能過幾年就因為電腦計算能力的增強而變得不安全了(暴力破解),為了因應這個情況,後來有人提出了 bcrypt 的加密方式來解決這問題
bcrypt 可以調整 cost 並且每次都有隨機的 salt,讓同樣的密碼產生出不同的結果
source: https://stackoverflow.com/questions/27592732/what-should-be-stored-in-table-while-using-bcrypt
當然不只 bcrypt 可以做到,目前還有 PBKDF2 與 Scrypt 可以達到相似的效果,因為是淺談,所以就不深入了。
From the scrypt paper: estimated cost of hardware to crack a password in 1 year.
假設 bcrypt 加密過的密碼真的也洩漏了,根據上圖可以看得出來原始密碼長度會影響到解密的時間,而為了解決這個問題,可以搭配 HMAC 來解決這問題,具體的演算法如下:
bcrypt(HMAC(password, key), salt) = hash
拿到加密過密碼的人,需要先反解 bcrypt 的值,HMAC(password, key),接著在取得 key,最後在反推 password,透過以上的方式讓密文即使被竊取走了,也不會有立即性的危險。
關於後者 crypto,就以後再說了…
參考文件:
https://blog.mozilla.org/webdev/2012/06/08/lets-talk-about-password-storage/