很久以前看到一篇文章,講某個大網站儲存用戶口令時,會經過十分復雜的處理。怎么個復雜不記得了,大概就是將口令先 Hash,結果加上一些特殊字符再 Hash,然后中間插入些字符再 Hash、再怎么怎么的。。。看的眼花繚亂。
當時心想這么復雜應該很安全了吧。事實上即使現在,仍有不少人是這么認為的。所以在儲存賬號口令時,經常會弄些千奇百怪的組合。
不過,千奇百怪的 Hash 算法究竟有意義嗎?在什么情況下能派上用場?是否有更簡單合理的替代方案?這問題先從拖庫說起。
知道算法才能破解
數據庫中的口令,都是以 Hash 形式儲存的。拖下數據庫后,如果要猜某個賬號的明文口令,得通過跑字典的方式:
for each word in 常用詞匯
if H(word) == E
print "明文:",word
exit
不過,光有泄露的數據 E 不夠,還得知道算法 H 才能跑的起來。光有 Hash 值,卻不知道用的是那種 Hash 算法,仍然無從下手。
當然很多小網站,數據庫和算法在同個系統里,一旦入侵兩者都泄露了;但若數據庫和算法不在同個系統里,即使能拖庫也未必知道算法。
猜算法
不過即使搞不到算法,也可以嘗試猜測。比如先在網站上注冊個賬號 —— 例如口令為 123456,然后在泄露的庫中,根據用戶名找到對應口令的 Hash 值,例如 dd6e5e5918e94d997c686fcebc56922f。
這時,就可以暴力猜算法了:
for each fn in 常用算法
if fn("123456") == dd6e5e5918e94d997c686fcebc56922f
print "算法:", fn
exit
不難猜出,fn 為 f(x) = md5(sha256(x))
。知道了算法,就可愉快的跑字典了。
奇怪算法
這時「奇怪算法」的優勢就體現出來了。 如果使用的算法十分奇葩,比如:
f(x) = md5("hello~" + sha1(sha256(x)) + "world!")
根本不在常用算法里,幾乎難以窮舉到,于是就能躲過「猜算法」這種攻擊方式。
所以,奇怪的算法是有意義的!
不過奇怪、奇葩、變態...這些都是人的主觀感覺,并不能用理性來衡量。比如說剛才那個算法有多復雜?你只能說很復雜,而難以給出一個準確的程度。
算法簡單,數據復雜
通過混合拼湊多個函數,來制造復雜程度,終究不是最合適的。
不妨把復雜轉移到數據上,例如上述的 "hello~" 和 "world!",如果換成更長、更沒意義、更難猜測的數據,不也能制造復雜嗎?
所以,最終可以把函數精簡到只剩一個,取而代之的是復雜的數據,例如:
f(x) = sha256(x + "18bc0a594ab5f65d868820b238b696e391eabb962e1d15c2c474a04735c1128f")
這串數據稱之為密鑰。密鑰是隨機生成的,沒有任何意義,并且絕不能對外透露。
這樣,復雜程度就能在密鑰空間上體現出來,而不是難以衡量的奇怪函數組合。
不過這里有個疑惑,為什么「密鑰」加在原文后面,而不是前面、或者夾在中間?如果僅僅是看著舒服,那還是存在主觀因素的。
HMAC
事實上,密碼學家早已提供支持兩個參數的 Hash 用法 —— HMAC,它比簡單粗暴的拼接靠譜得多。于是上述可改進成:
f(x) = hmac_sha256(x, "18bc0a594ab5f65d868820b238b696e391eabb962e1d15c2c474a04735c1128f")
HMAC 第二個參數本身就是 Key 的意思,所以用在這里恰到好處。
當然,如果不保護好算法以至于很容易泄露,那么無論用奇怪組合還是這種方式,也都無濟于事。
保護算法
很多人對算法保護的并不好,甚至直接寫在了諸如 PHP 腳本里,只要有文件讀取權限,就能搞到算法。
如果稍加隱蔽,例如通過本地服務,并控制好可執行程序的權限,或許就更難找到了。
更進一步,可以單獨部署一臺服務器,專門提供 HMAC 計算。通信接口足夠簡單,簡單到幾乎不可能出漏洞;并且不開放其他任何服務,只能人工管理。這樣,被入侵的可能性就更小了。
當然,管理員人為泄密也是有可能的。如果要有一個終極方案,或許應該將計算交給一個獨立的硬件。這個硬件是個黑盒設備,輸入明文、輸出 Hash 結果。算法、密鑰這些都隱藏在其內部,拆開即自毀,這樣管理員也無從知曉。例如 HSM(hardware security module)設備,就能將算法以及密鑰進行物理隔離。
password |-------------------------|
----------->| 黑盒設備 |
| KEY = ***************** |
<-----------| hmac_sha(password, KEY) |
hash |-------------------------|
其他策略
如果算法能保證 100% 不泄露,那么加鹽、慢 Hash 這些都可以省略了,因為密鑰本身就足以對抗暴力破解。
當然現實中沒有絕對的事。如果算法真的泄露了,現有數據的風險就大幅增加。所以本該有的策略還是得有,不能把風險全押在一個點上。
所以加鹽、慢 hash 這些仍然是需要的。最終方案應該類似這樣:
# 業務邏輯
hash = pbkdf(password, salt, cost...)
↓
######## 隱蔽的黑盒系統 ########
hash = hmac(hash, KEY)
##############################
↓
# 返回業務
這樣即使黑盒算法遭到泄露,破解仍然需要很大成本。
破解成本
不過,奇怪算法也有一個優勢,那就是破解軟件支持程度不高。
傳統的權威算法,早已成為眾矢之的,有各種高度優化的破解方案,因此破解速度會非常快;而奇怪算法,則不在優化范圍中,因此速度會慢的多。
所以,在權威算法之后,可以考慮再混合少量奇怪算法。這樣,就能再增加一層破解障礙。
總結
奇怪算法是有意義的,但效果難以衡量
HMAC 的密鑰需要足夠長、足夠隨機、足夠保密
保護好算法,和保護數據庫同樣重要
文章列表