MD5 vs SHA-256 vs SHA-512 — 雜湊函數解析
雜湊函數在軟體開發中無所不在:檔案完整性檢查、密碼儲存、數位簽章、API 認證、快取鍵、去重。然而多數開發者將它們視為黑盒 — 你餵入一個字串,你拿回固定長度的十六進位摘要。「使用哪個」雜湊函數,以及「避免使用哪個」,這些細節其實非常重要。
MD5 已被破解。SHA-1 已被棄用。SHA-256 與 SHA-512 目前安全。如果你想為未來鋪路,還有 SHA-3 可用。但「破解」在不同情境下並非同義 — MD5 在某些用例中尚可,在其他用例中卻會造成嚴重錯誤。本指南解說重要的特性、各個函數在這些特性下的表現,並提供你在 2026 年挑選正確雜湊的明確決策架構。
雜湊函數實際上的功能
密碼學雜湊函數會將任意長度的輸入映射為固定長度的輸出(摘要或雜湊)。「密碼學安全」雜湊函數有三項定義特性:
- 原像抗性 — 給定雜湊
h,在運算上應不可行找到任何輸入m使hash(m) = h。這就是「單向」特性。 - 第二原像抗性 — 給定輸入
m1,應不可行找到不同輸入m2使hash(m1) = hash(m2)。 - 碰撞抗性 — 應不可行找到「任何」兩個不同輸入
m1與m2使hash(m1) = hash(m2)。
任何未能滿足這些特性之一的函數,在密碼學用途中都被認為已被破解。請注意,「不可行」在此有特定意義:它不代表數學上不可能,而是代表所需運算量超出目前或可預見硬體的實務範圍。
此外,密碼學雜湊函數展現雪崩效應:輸入中的單一位元變動會產出在其位元中約有一半相異的輸出。這確保相似的輸入產出完全不同的摘要。
輸入: "hello"
MD5: 5d41402abc4b2a76b9719d911017c592 (128 位元 / 32 個十六進位字元)
輸入: "Hello"
MD5: 8b1a9953c4611296a827abf8c47804d7 (改變一個字元 = 完全不同的輸出) MD5 — 快速、普及,且已被破解
歷史與設計
MD5(Message Digest 5)由 Ron Rivest 於 1991 年設計,產出 128 位元(16 位元組)的摘要。1990 年代多數時期它是檔案完整性驗證、憑證簽章與密碼雜湊的標準選擇。它極為快速 — 現代 CPU 每秒可運算數千萬次 MD5 雜湊,GPU 可運算數十億次。
為什麼 MD5 被破解
2004 年,王小雲及其同事展示了針對 MD5 的實際碰撞攻擊 — 兩個不同的檔案產出相同的 MD5 雜湊。該攻擊在一般消費級硬體上幾分鐘就能執行。2008 年,研究者使用 MD5 碰撞建立了流氓 CA 憑證,證明真實世界的 PKI 基礎設施會受影響。到 2012 年,Flame 惡意軟體利用 MD5 碰撞偽造了微軟的程式碼簽署憑證。
NIST 正式為多數密碼學用途棄用 MD5。憑證頒發機構在 2009 年停止頒發 MD5 簽署的憑證。瀏覽器廠商在 2011 年左右移除了對 MD5 憑證簽章的支援。
MD5 仍可接受的時機
MD5 並非全然無用。對於非資安的 checksum — 在檔案傳輸中偵測意外資料毀損、在快取系統中對攻擊者無法影響輸入的內容定址、或在封閉的內部系統中產生唯一識別碼 — MD5 仍算可接受。關鍵測試:如果攻擊者能透過建立碰撞獲益,就不要使用 MD5。如果只在意意外毀損,MD5 可以使用。
- 安全:內部去重、快取鍵、非資安的檔案變更偵測
- 不安全:憑證、數位簽章、密碼雜湊、檔案真實性驗證、資安令牌
SHA-1 — 已棄用,但尚未死透
SHA-1 產出 160 位元摘要,是 MD5 的後繼者。它在 2000 年代多數時間都是憑證簽章與程式碼簽署的標準。2017 年,SHAttered 攻擊展示了首個實際的 SHA-1 碰撞,使用約 110 GPU 年的運算量產出兩個具相同 SHA-1 雜湊的不同 PDF 檔案 — 雖然昂貴,但仍在國家層級預算範圍內,且日益可及。
SHA-1 已被 NIST 與所有主要憑證頒發機構棄用。它不應用於憑證、程式碼簽署或任何新的資安敏感應用。某些舊系統仍在內部使用 SHA-1,但強烈建議遷移到 SHA-256。Git 仍使用 SHA-1 進行物件定址(不過 SHA-256 遷移正在進行中),但這正在逐步淘汰。
SHA-256 — 目前的標準
SHA-256 屬於 SHA-2 家族,由 NSA 設計,並由 NIST 在 FIPS 180-4 中標準化。它產出 256 位元(32 位元組)摘要。自 2001 年發布以來,SHA-256 已經過密集分析,目前尚未發現實際攻擊。它是以下用途的事實標準:
- TLS 憑證(現今所有頒發的憑證實質上都使用 SHA-256)
- 程式碼簽署(Windows Authenticode、Apple notarization、JARs)
- API 認證的 HMAC-SHA256(AWS Signature v4、GitHub webhook 驗證)
- JWT 令牌簽章(HS256 與 RS256 內部都使用 SHA-256)
- 區塊鏈交易 ID(比特幣使用雙重 SHA256)
- 套件管理器中的檔案完整性驗證(npm、pip、apt)
輸入: "hello"
SHA-256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
(256 位元 / 64 個十六進位字元)
SHA-512: 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d
99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
(512 位元 / 128 個十六進位字元) SHA-256 的效能
SHA-256 內部使用 32 位元字組運算。在 32 位元硬體或沒有硬體加速的舊 CPU 上,它明顯比 MD5 慢。在具備 SHA 擴充的現代 64 位元 CPU 上(Intel Goldmont+、AMD Zen+、Apple Silicon、ARM Cortex-A57+),SHA-256 經硬體加速後極快 — 常接近 MD5 速度。多數伺服器環境都具備硬體加速,因此實務上 SHA-256 對幾乎所有應用都足夠快。
SHA-512 — 更寬,有時更快
SHA-512 產出 512 位元(64 位元組)摘要,內部使用 64 位元字組運算。在沒有 SHA 擴充的 64 位元硬體上,SHA-512 可能比 SHA-256 更快,因為其 64 位元運算更能善用現代暫存器寬度。在具 SHA 擴充的硬體上,SHA-256 通常較快,因為擴充功能特別為 SHA-256 最佳化。
SHA-512 提供更大的資安裕度 — 256 位元碰撞抗性,相較 SHA-256 的 128 位元。對多數目前的威脅模型而言,SHA-256 的 128 位元碰撞抗性已綽綽有餘(破解它需要約 2^128 次運算)。SHA-512 適用於:
- 你瞄準 64 位元伺服器,並希望在無硬體擴充時取得最大吞吐量
- 你需要較長的摘要作為其他密碼學運算的金鑰材料
- 你想為必須保護數十年的資料取得額外資安裕度
- 你實作特別要求 SHA-512 的協定(例如某些 TLS 密碼套件)
SHA-384 與 SHA-512/256
SHA-384 是 SHA-512 的截斷版本,產出 384 位元 — 在你想要 SHA-512 的 64 位元內部運算但需要較短輸出時很有用。SHA-512/256 是另一種截斷變體,使用 SHA-512 的內部運算產出 256 位元輸出。SHA-512/256 抵抗影響 SHA-256 的長度延伸攻擊,在長度延伸是疑慮的情境中很有用(雖然 HMAC 在多數實務情境中已能緩解此問題)。
SHA-3 — 不同架構、面向未來
SHA-3(2015 年標準化於 NIST FIPS 202)使用 Keccak 海綿建構 — 與 SHA-2 的 Merkle-Damgard 結構基本不同的設計。這很重要,因為任何未來在 Merkle-Damgard 設計中發現的弱點都會同時影響 MD5、SHA-1 與 SHA-2,而 SHA-3 仍會不受影響。
SHA-3 目前安全,並且是需要長期保證或想對未來 SHA-2 弱點避險的新系統的正確選擇。在純軟體實作中比 SHA-256 慢。SHA-3 出色之處在於硬體實作 — 其設計在矽晶片中極為高效。SHA-3-256 與 SHA-3-512 產出與其 SHA-2 對應版本相同的摘要大小。
比較表
| 演算法 | 輸出 | 碰撞抗性 | 狀態 | 軟體速度 | 用於密碼? |
|---|---|---|---|---|---|
| MD5 | 128 位元 | 已破解 | 已棄用 | 極快 | 永不 |
| SHA-1 | 160 位元 | 已破解 | 已棄用 | 快 | 永不 |
| SHA-256 | 256 位元 | 128 位元 | 目前標準 | 快(硬體加速) | 永不(太快) |
| SHA-512 | 512 位元 | 256 位元 | 安全 | 64 位元上快 | 永不(太快) |
| SHA-3-256 | 256 位元 | 128 位元 | 面向未來 | 中等(軟體) | 永不(太快) |
| bcrypt | 60 字元字串 | 不適用 | 僅密碼 | 刻意設計為慢 | 是 |
密碼雜湊:截然不同的問題
這值得獨立成節,因為這是開發者最常犯的錯誤之一。SHA-256 是檔案完整性檢查、API 簽署與憑證驗證的正確工具。但它「不」是雜湊密碼的工具,用於該用途會造成真實的資安事件。
問題在於速度。SHA-256 設計為快速 — 現代 GPU 每秒可運算數十億次 SHA-256 雜湊。取得你已雜湊密碼資料庫的攻擊者每秒可嘗試數十億次密碼猜測。即使是長且隨機的密碼,在雜湊很快的情況下也能被快速破解。
// 切勿對密碼這樣做
const hash = crypto.createHash('sha256').update(password).digest('hex'); // 對密碼使用 bcrypt、scrypt 或 Argon2
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12); // 成本因子 12 Bcrypt 測試工具讓你能在瀏覽器中雜湊與驗證 bcrypt 密碼。對於理解 bcrypt 成本因子及其運算時間,在設定應用程式的工作因子時是有用的參考。
HMAC:為雜湊新增認證
一般雜湊無法證明是誰運算的 — 任何擁有資料的人都能運算出相同的 SHA-256 雜湊。HMAC(基於雜湊的訊息認證碼)為運算新增密鑰,產出只有知道金鑰者才能重現的標籤。HMAC-SHA256 是以下用途的標準:
- Webhook 簽章驗證(GitHub、Stripe、Shopify 都使用 HMAC-SHA256)
- AWS Signature Version 4(請求簽署)
- JWT HS256 令牌(標頭 + 載荷的 HMAC-SHA256)
- Cookie 完整性(簽署 session cookie 以防止竄改)
const crypto = require('crypto');
// 使用 HMAC-SHA256 簽署訊息
const mac = crypto
.createHmac('sha256', secretKey)
.update(message)
.digest('hex');
// 驗證:以固定時間比較(防止時序攻擊)
const isValid = crypto.timingSafeEqual(
Buffer.from(mac, 'hex'),
Buffer.from(received, 'hex')
);
請注意比較時使用 timingSafeEqual。使用一般字串相等檢查比較 MAC 值會洩漏可在時序攻擊中被利用的時序資訊。在驗證 MAC 時請務必使用固定時間的比較函數。使用 HMAC 產生器運算 HMAC-SHA256 值以利測試與除錯,無需撰寫程式碼。
實務建議
一般檔案完整性(checksum)
使用 SHA-256。它是套件驗證的標準(npm lockfiles、pip requirements 雜湊、Docker 映像層)。SHA-256 雜湊工具能在瀏覽器中為文字輸入或字串值運算 SHA-256 摘要。對於速度關鍵且你信任來源的快速非資安 checksum,MD5 仍可接受,但在任何共享或自動化情境中,SHA-256 較佳。
TLS 憑證與程式碼簽署
SHA-256 是必要標準。所有憑證頒發機構都頒發 SHA-256 憑證。新憑證切勿使用 MD5 或 SHA-1 — 現代瀏覽器與作業系統會拒絕它們。
API 認證
使用 HMAC-SHA256。它是既定標準,在所有語言中都有良好支援,並且是多數 API 資安文件預期的演算法。使用 MD5 雜湊工具或 SHA-256 雜湊工具運算摘要以利快速比較,使用 HMAC 產生器產生 HMAC 簽章。
密碼雜湊
使用 bcrypt(成本因子 12+)、scrypt 或 Argon2id。即使加上鹽,也切勿直接對密碼使用 MD5、SHA-1、SHA-256 或 SHA-512。Bcrypt 測試工具能在開發期間協助你驗證 bcrypt 雜湊。
需要數十年資安保護的長期資料
優先使用 SHA-512 或 SHA-3-256。較大的摘要大小為密碼分析進展提供額外裕度。NIST 為需要長期資安的應用建議 SHA-512 與 SHA-3。請參閱 NIST FIPS 180-4 中 SHA-2 演算法的權威規格。
無遺留限制的新系統
一般用途使用 SHA-256。密碼使用 Argon2id。認證碼使用 HMAC-SHA256。如果你想為未來鋪路且能接受略低的效能,SHA-3-256 對於通用雜湊是堅實的 SHA-256 替代方案。