如果你只想知道答案:MD5 用於任何需要對抗惡意攻擊者的場景都不安全,SHA-1 也一樣。這兩者都已被找出實際可行的碰撞攻擊,不應再用於數位簽章、防竄改驗證或密碼儲存。它們唯一還算堪用的場景,是在沒有惡意對手的前提下做快速校驗,例如確認檔案在傳輸過程中沒有意外損壞。
至於為什麼,以及什麼才是正確做法,下面逐一說明。
雜湊函數把任意輸入壓成固定長度的輸出,由於輸入無限多、輸出數量有限,理論上一定存在兩個不同輸入產生相同雜湊值的情況,這就叫「碰撞」(Collision)。碰撞無法完全避免,但一個安全的雜湊函數必須讓「刻意製造碰撞」在計算上不可行。
所謂「被攻破」,指的就是有人找到了比暴力破解快得多的方法來製造碰撞:
碰撞為什麼危險?想像攻擊者準備兩份合約,一份無害、一份惡意,兩者 MD5 相同。他讓你對無害版本簽章,事後卻把簽章套到惡意版本上——因為雜湊值一樣,簽章照樣驗證通過。這就是碰撞攻擊的實際威脅。
雜湊雖然不可逆,但如果密碼太常見,攻擊者可以「事先把答案算好」。做法是預先計算海量常見密碼的雜湊值,存成一張對照表,破解時直接查表即可。最有名的優化版本叫「彩虹表」(Rainbow Table),它用一種時間換空間的鏈結技巧,大幅縮小儲存量。
結果就是:若你的網站直接把密碼的 MD5 或 SHA-256 存進資料庫,一旦資料庫外洩,攻擊者拿現成的彩虹表一查,大量弱密碼瞬間還原成明文。這裡的問題不在於演算法被攻破,而在於「沒有加鹽」以及「演算法太快」。
「鹽」(Salt)是一段隨機字串,在計算雜湊前先和密碼拼接在一起。例如使用者密碼是 1234,系統幫他產生隨機鹽 a8Kx9q,實際儲存的是 hash("1234" + "a8Kx9q"),並把鹽一起存起來。
加鹽帶來兩個關鍵效果:
1234,但鹽不同,存進資料庫的雜湊值也不同,攻擊者無法靠「哪些帳號雜湊一樣」來鎖定弱密碼。鹽不需要保密,重點是它必須隨機、夠長,而且每個使用者都不一樣。
就算加了鹽,MD5、SHA-256 這類通用雜湊還是不適合存密碼,原因是它們「太快」。這些演算法設計目的是高速處理大量資料,但快對密碼來說是缺點——攻擊者拿到外洩的雜湊後,可以用 GPU 每秒嘗試數十億組密碼來暴力破解。
正確做法是使用專為密碼設計的「慢速」雜湊函數,它們刻意耗費運算資源,可調整成本參數讓單次運算花上零點幾秒,對正常登入無感,卻讓大規模暴力破解變得極度昂貴:
這些函數通常內建鹽的處理,你不必自己拼接,使用對應函式庫即可。
| 演算法 | 類型 | 抗碰撞 | 適合存密碼 |
|---|---|---|---|
| MD5 | 通用雜湊 | 已攻破 | 否 |
| SHA-1 | 通用雜湊 | 已攻破 | 否 |
| SHA-256 | 通用雜湊 | 目前安全 | 否(太快) |
| SHA-512 | 通用雜湊 | 目前安全 | 否(太快) |
| bcrypt | 密碼雜湊 | 不適用 | 是 |
| Argon2 | 密碼雜湊 | 不適用 | 是(首選) |
注意「抗碰撞」與「適合存密碼」是兩個不同維度。SHA-256 抗碰撞沒問題,可以放心用於檔案校驗與數位簽章,但因為運算太快,並不適合直接拿來存密碼。
想實際體驗 MD5 與 SHA 系列算出來的差異,可以用本站工具同時計算多種演算法,直觀比較它們的輸出長度與結果。
立即使用雜湊值產生器