我們一度用 MD5 做安裝檔校驗。有天同事說「雜湊對不上,這個包有問題」,於是整個團隊把 CDN 翻了一遍,最後原因是他下載的其實是 CDN 回傳的 404 頁面——一個只有幾百位元組的 HTML,雜湊當然完全不同。另一次更麻煩:舊系統把使用者密碼直接存 MD5,被拖庫後不到兩天就有人用現成的碰撞表還原出弱密碼。這兩件事讓我把「雜湊用來做什麼」和「該用哪種演算法」分得很清楚:校驗傳輸有沒有壞,和防止別人偽造內容,是完全不同的兩個要求。
一、雜湊的三個性質,決定了它只能做這三類事
- 定長:不管輸入 3 個位元組還是 3 個 GB,SHA-256 輸出永遠是 256 位,也就是 64 個十六進位字元。
- 單向:從摘要推不回原文。這和加密有本質區別——加密是可逆的,有金鑰能還原,目的是保密;雜湊的目的是「指紋」。
- 雪崩效應:原文改 1 個字元,摘要會有大約一半的位發生變化。空字串的 MD5 是
d41d8cd98f00b204e9800998ecf8427e、SHA-256 是e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,而末尾只多加一個空格,出來的就是兩串毫不相干的值。這兩個固定值還能當自我檢查用:算出來對不上,說明工具或輸入環節有問題。
因此它能可靠回答三個問題:這兩份內容是否一致;這份內容是否被改動過;以及在不暴露原文的前提下能否證明我知道原文。它不能回答的問題是「這段密文是什麼」。
二、MD5 不安全到什麼程度,還剩下什麼用
| 演算法 | 輸出 | 十六進位長度 | 現況 | 適合的用途 |
|---|---|---|---|---|
| MD5 | 128 位 | 32 字元 | 碰撞可在普通硬體上構造,簽章憑證領域已宣告失效 | 非對抗情境的完整性校驗、資料去重分桶 |
| SHA-1 | 160 位 | 40 字元 | 同樣存在實際碰撞,主流瀏覽器與憑證體系已淘汰 | 相容舊系統的校驗值 |
| SHA-256 | 256 位 | 64 字元 | 目前推薦,廣泛用於簽章、區塊摘要、製品校驗 | 安全情境的預設選擇 |
| SHA-512 | 512 位 | 128 字元 | 強度更高,摘要更長、傳輸與人工核對成本上升 | 高強度要求、需要更長摘要時 |
「碰撞」指有人刻意構造出兩個內容不同、摘要卻相同的輸入。一旦可被製造,「摘要相同即內容可信」這個前提就被破壞——這才是 MD5 被趕出安全情境的原因。但反過來看,下載中斷、CDN 回源錯誤、檔案被腳本誤改,這些都不是有人在構造碰撞,MD5 依然夠用。真正的分歧點只有一個:有沒有對手會主動構造第二份內容。
三、密碼儲存是第三件事,別混進來
把 MD5 或 SHA-256 拿來存密碼,是同一個系列裡最貴的誤用。快的雜湊恰恰是攻擊者的朋友:一張消費級顯示卡每秒能試算海量候選,撞庫腳本配上現成的彩虹表,常見弱密碼幾乎瞬間還原。正確做法是用加鹽的慢雜湊——bcrypt、scrypt、Argon2id 這類自帶鹽值並可調工作因子的演算法,讓每次驗證都要付出可控的計算成本。鹽的作用是相同密碼得到不同摘要,從而廢掉批次預先計算;它不是金鑰,可以明文儲存。
四、我的實際流程
- 拿到校驗值先確認演算法名稱與格式。很多「對不上」來自 16 位與 32 位混用:所謂 16 位 MD5 只是取 32 位結果的第 9 到第 24 個字元,天生就「對不上」完整值;同理還有大小寫顯示差異,
a–f與A–F表達的是同一個摘要。 - 文字類要在同一個工具裡一次算完再比。我的習慣是把待校驗內容貼進雜湊計算器,MD5、SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 六種摘要一次列出來,逐行和對方公布的值對照,需要哪一行就單獨複製哪一行。很多歷史系統只給 MD5,而新規範要求 SHA-256,一次全出就不用反覆換工具重算第二遍;比對時順手把大小寫統一,能省掉一半「看著不一樣」的誤判。
- 檔案走檔案校驗。安裝檔這類幾百 MB 的東西用檔案 MD5 計算,可以一次拖進多個檔案同時得到 MD5、SHA-1、SHA-256,比對是否下錯包時很直觀。
- 介面簽章用 HMAC,不用裸雜湊拼金鑰。
md5(secret + params)這種寫法有過被繞過的記錄(涉及長度擴充等構造方式),改用 HMAC-SHA256 就把金鑰的參與方式交給一個專門設計過的結構。在同一個計算器裡填金鑰即可得到 HMAC 值,用來核對用戶端簽章。
五、常見疑問
Q:雜湊和加密到底有什麼區別?
雜湊單向、定長、不需要金鑰,用於校驗與指紋;加密可逆、需要金鑰,用於保密傳輸與儲存。要還原內容就只能用加密,不能指望「解雜湊」。
Q:SHA-256 能反推出原文嗎?
不能。只能靠窮舉候選再比對摘要,所以原文本身的隨機度決定安全性——密碼太短,換 SHA-256 也一樣被撞出來。
Q:檔案校驗值對不上,先懷疑什麼?
先懷疑「比的不是同一個東西」:下載到了錯誤頁或被截斷、文字換行符被改(CRLF 與 LF 會讓純文字摘要完全不同)、編碼從 UTF-8 變成 GBK、以及 16 位對 32 位。把檔案大小和行數先看一眼,能排除八成的誤報。
Q:能不能自己發明一種雜湊方案?
不建議。安全強度來自公開演算法經過多年攻擊驗證,而不是把幾個摘要串起來或自訂排序這類組合,後者往往引入了新的可構造點。選 SHA-256 或 SHA-512,加 HMAC,再用成熟的密碼雜湊演算法,覆蓋絕大多數需求。
Q:資料去重、找重複檔案也要用 SHA-256 嗎?
不涉及對手時用 MD5 更快也更省事,只需要「兩份內容是否相同」。真正要防篡改的地方才需要升級到 SHA-256,這時也要一併考慮摘要本身的分發管道是否可信。
那兩次事故給我的結論很樸素:先說清楚這次比對是為了「防傳輸出錯」還是「防人為偽造」,演算法的選擇自己就會定下來;而「對不上」的時候,第一個動作應該是確認兩邊算的是不是同一段位元組,而不是先懷疑演算法被攻破。