Hash 雜湊演算法完整比較:MD5 / SHA1 / SHA256 / SHA512 該選哪個?
寫給:仍在用 MD5 存使用者密碼的後端工程師、不確定 git SHA-1 安不安全的 DevOps、想知道下載檔案 hash 驗證怎麼做的所有用戶。
Hash(雜湊)演算法是把任意大小資料壓縮成固定長度指紋的單向函數。它支撐了 Git 版本管理、HTTPS 證書、區塊鏈、檔案完整性檢查、密碼儲存等幾乎所有現代資安基礎。但 hash 演算法不是一視同仁——MD5 早在 2004 年被破、SHA1 在 2017 年被 Google + 阿姆斯特丹大學暴力破解,仍用這些演算法等於把家門鑰匙貼公告欄。本文 14 分鐘把所有主流 hash 演算法的速度、安全、用途一次講清楚。
1. Hash 是什麼
Hash 函數有四個必要性質:
- 確定性:同樣輸入永遠產生同樣輸出
- 快速計算:常數時間
- 不可逆:從 hash 推不回原文(單向函數)
- 碰撞抗性:找到兩個不同輸入產生同樣 hash 極困難
舉例 SHA-256:
echo -n "hello" | shasum -a 256
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
不論輸入 1 byte 或 1GB,輸出永遠 256 bit(64 個 hex 字元)。即使輸入只差一個字,輸出完全不同(雪崩效應):
echo -n "hello" | shasum -a 256 # 2cf24dba5fb...
echo -n "hellp" | shasum -a 256 # b1a8d6c5d22...
Hash 的常見用途:
- 檔案完整性驗證(下載 ISO 後比對)
- Git commit ID(SHA-1 / SHA-256)
- 密碼儲存(不存明文)
- 區塊鏈共識(PoW)
- 內容定址(IPFS)
- Bloom filter、HashMap 索引
2. 5 個核心觀念
2.1 演算法總覽
| 演算法 | 輸出長度 | 設計年份 | 狀態 | 用途 |
|---|---|---|---|---|
| MD5 | 128 bit | 1992 | 已破 | 非安全場景(checksum) |
| SHA-1 | 160 bit | 1995 | 已破 | git(漸進淘汰) |
| SHA-256 | 256 bit | 2001 | 安全 | 大部分場景 |
| SHA-512 | 512 bit | 2001 | 安全 | 高安全需求 |
| SHA-3 (Keccak) | 224/256/384/512 bit | 2015 | 安全 | 不同設計基礎 |
| BLAKE2 | 256/512 bit | 2012 | 安全 | 比 SHA-256 快 3 倍 |
| BLAKE3 | 256 bit(可變) | 2020 | 安全 | 比 BLAKE2 快 10 倍 |
| xxHash | 32/64/128 bit | 2012 | 非加密 | 純為速度(HashMap) |
選擇原則(2026 年):
- 一般 hash:SHA-256 或 BLAKE3
- 密碼存儲:argon2id 或 bcrypt(不是 hash 函數!)
- 非加密快速 hash:xxHash / FarmHash
2.2 為什麼 MD5 / SHA-1 不能用
碰撞攻擊歷史:
- MD5:2004 年 Xiaoyun Wang 等中國研究團隊找到實際碰撞,2012 年 Flame 惡意程式偽造 Microsoft 證書
- SHA-1:2017 年 Google SHAttered 計畫公開找到兩個不同 PDF 有相同 SHA-1,成本約 11 萬美金(2026 年估算降到約 5 萬)
對攻擊者意義:可以偽造合法檔案。下載者比對 hash 看似一致,實際內容已替換。
只有一個場景仍可用 MD5/SHA-1:純粹做 cache key / 索引,不涉及安全信任。
2.3 SHA-256 vs SHA-512
兩者來自同一家族(SHA-2),主要差別:
| 屬性 | SHA-256 | SHA-512 |
|---|---|---|
| 輸出長度 | 32 byte | 64 byte |
| 內部 word | 32 bit | 64 bit |
| 在 64-bit CPU 速度 | 慢 | 快 30% |
| 在 32-bit / IoT 設備 | 快 | 慢 |
| 安全強度 | 128 bit | 256 bit |
2026 年伺服器幾乎都 64-bit,SHA-512 更快。但 SHA-256 是事實標準(HTTPS 證書、區塊鏈),相容性最廣。
2.4 密碼雜湊:bcrypt / argon2,不是 SHA
這是新手最常犯的錯誤。用 SHA-256 存密碼等於用紙糊保險箱:
- SHA-256 設計目標是快(每秒可算數十億次)
- 攻擊者用 GPU 字典攻擊一秒試 100 億組密碼
- 加 salt 也救不了,依然是秒級破解
正確做法用故意慢的密碼雜湊函數:
| 函數 | 年份 | 推薦設定 |
|---|---|---|
| bcrypt | 1999 | cost factor 12 |
| scrypt | 2009 | N=2^17, r=8, p=1 |
| Argon2id | 2015(PHC 競賽冠軍) | m=64MB, t=3, p=4 |
argon2id 是 2026 年最推薦選擇。它同時抵抗 GPU 與 ASIC 攻擊。
import argon2
ph = argon2.PasswordHasher()
hash = ph.hash("user-password")
# $argon2id$v=19$m=65536,t=3,p=4$...
try:
ph.verify(hash, "user-password")
print("OK")
except argon2.exceptions.VerifyMismatchError:
print("Wrong password")
2.5 Salt + Pepper
Salt:每個使用者一個隨機字串,防 rainbow table 攻擊。bcrypt / argon2 自動加 salt。
Pepper:所有使用者共用一個秘密字串,存在程式碼或 HSM 而非 DB。若 DB 被偷,攻擊者沒有 pepper 仍無法 brute force。
import argon2, hmac, hashlib
PEPPER = os.environ["APP_PEPPER"] # 32+ byte 隨機字串
def hash_password(password):
peppered = hmac.new(PEPPER.encode(), password.encode(), hashlib.sha256).hexdigest()
return argon2.PasswordHasher().hash(peppered)
3. 實戰範例
範例 1:下載檔案後驗證 SHA-256
# 下載 Ubuntu ISO
curl -O https://releases.ubuntu.com/24.04/ubuntu-24.04-desktop-amd64.iso
# 算 sha256
shasum -a 256 ubuntu-24.04-desktop-amd64.iso
# 9bc...
# 比對官方公告
echo "9bc...example ubuntu-24.04-desktop-amd64.iso" | shasum -a 256 -c
# ubuntu-24.04-desktop-amd64.iso: OK
範例 2:Python 對檔案做 hash
import hashlib
def file_hash(path, algo="sha256", chunk=8192):
h = hashlib.new(algo)
with open(path, "rb") as f:
while data := f.read(chunk):
h.update(data)
return h.hexdigest()
print(file_hash("data.bin"))
print(file_hash("data.bin", "blake2b"))
chunk 控制記憶體用量,1GB 檔案不會 OOM。
範例 3:HMAC 簽章(防偽造)
import hmac, hashlib
key = b"my-secret-key"
message = b"transfer 1000 to alice"
sig = hmac.new(key, message, hashlib.sha256).hexdigest()
print(sig)
# 驗證
expected = hmac.new(key, message, hashlib.sha256).hexdigest()
if hmac.compare_digest(sig, expected):
print("Valid")
HMAC 比直接 hash(key + message) 安全(避免長度延伸攻擊)。
範例 4:Argon2 密碼雜湊(生產用)
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError, InvalidHashError
ph = PasswordHasher(memory_cost=65536, time_cost=3, parallelism=4)
# 註冊
hashed = ph.hash("user-input-password")
db.save_user(username, hashed)
# 登入
stored = db.get_user_hash(username)
try:
ph.verify(stored, "user-input-password")
if ph.check_needs_rehash(stored):
new_hash = ph.hash("user-input-password")
db.update_hash(username, new_hash)
return True
except (VerifyMismatchError, InvalidHashError):
return False
check_needs_rehash 是好習慣:當你升級 parameters 時,登入時自動重 hash。
範例 5:Git 加 SHA-256 取代 SHA-1
# 創建 SHA-256 倉庫(Git 2.29+)
git init --object-format=sha256 my-repo
cd my-repo
echo "hello" > file.txt
git add . && git commit -m "init"
git log --oneline
# 4d186321... init ← 64-char SHA-256,不再是 40-char SHA-1
GitHub 2026 已支援 SHA-256,但跨 server 推送仍需配對相同 format。
4. 進階技巧
4.1 Constant-time 比較防 timing attack
import hmac
hmac.compare_digest(received_sig, expected_sig) # ✓
received_sig == expected_sig # ✗ 早 return
逐 byte 比較會在第一個不同字元 early return,攻擊者測時間差可一字一字猜中正確 sig。constant-time 比較永遠比完全長度。
4.2 BLAKE3 並行加速
import blake3
hasher = blake3.blake3()
with open("huge.bin", "rb") as f:
while chunk := f.read(65536):
hasher.update(chunk)
print(hasher.hexdigest())
# 並行
import blake3
blake3.blake3(b"data", max_threads=blake3.blake3.AUTO).hexdigest()
BLAKE3 在多核 CPU 可達 SHA-256 的 10 倍速。
4.3 增量 hash(resumable)
下載大檔案被中斷?hash 狀態可以 dump 出來下次續用:
import hashlib, pickle
h = hashlib.sha256()
h.update(b"first part")
# 保存中間狀態(Python 限定,需 hashlib >= 3.11)
state = h.copy()
# 繼續
state.update(b"second part")
print(state.hexdigest())
4.4 內容定址儲存(CAS)
IPFS、Git 都用 hash 當儲存 key。設計重點:
- 同樣內容只存一份(自動 dedup)
- 改任何一 byte 就變新 hash(不可變)
- 樹狀結構(Merkle tree)可做局部驗證
def store(data):
h = hashlib.sha256(data).hexdigest()
path = f"objects/{h[:2]}/{h[2:]}" # 分散到 256 子目錄
if not os.path.exists(path):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "wb") as f:
f.write(data)
return h
4.5 Bloom filter 結合 hash
判斷 element 是否在集合中、可容忍 false positive:
import mmh3 # MurmurHash3
class BloomFilter:
def __init__(self, size=10000, k=3):
self.bits = [0] * size
self.size = size
self.k = k
def add(self, item):
for i in range(self.k):
idx = mmh3.hash(item, i) % self.size
self.bits[idx] = 1
def maybe_contains(self, item):
return all(self.bits[mmh3.hash(item, i) % self.size] for i in range(self.k))
5. 常見錯誤與解法
錯誤 1:用 SHA-256 存密碼
症狀:DB 被偷後,攻擊者數小時內破解所有密碼。 根因:SHA-256 太快,配合 GPU 字典攻擊秒破。 解法:改用 argon2id(推薦)或 bcrypt。
錯誤 2:自己 salt 但結合方式錯
症狀:sha256(salt + password) 仍被破。
根因:長度延伸攻擊 + GPU 仍夠快。
解法:不要自己做密碼雜湊。使用標準 lib(argon2 / bcrypt)。
錯誤 3:用 hash 比較字串造成 timing attack
症狀:API key 驗證被時序攻擊推出正確值。
根因:用 == 比較。
解法:用 hmac.compare_digest。
錯誤 4:忘了 salt 隨機性
症狀:每個 user 用相同 salt(例如 user id)。 根因:開發圖方便。 解法:salt 必須是密碼學等級隨機(16 byte 以上)。bcrypt / argon2 自動產。
錯誤 5:MD5 用於檔案驗證 + 安全信任
症狀:依賴 MD5 驗證下載檔,被攻擊者偽造。 根因:MD5 已破。 解法:改用 SHA-256 並驗證簽章(GPG sign)。
6. 用 SuperTools 線上版完成相同任務
不想開 terminal?打開 SuperTools Hash 工具:
- 支援演算法:MD5 / SHA1 / SHA256 / SHA384 / SHA512 / BLAKE2 / BLAKE3
- 文字 / 檔案雙模式:拖檔上去即時算 hash
- HMAC 模式:填 key 算 HMAC-SHA256 等
- 批次比對:貼一個 expected hash,工具自動 highlight 一致與否
- 編碼選擇:hex / base64 / base64url
工具 client-side WebCrypto + WASM 跑,檔案不上傳。可拿來算公司內部檔案 checksum。
實際使用流程:
- 從官網複製預期的 SHA-256
- 開 supertools.tw/dev/hash 拖入下載的檔案
- 選 SHA-256
- 比對工具計算值與貼上的預期值
立即使用 SuperTools Hash 工具:https://supertools.tw/dev/hash
7. 其他語言實作
Python
import hashlib
hashlib.sha256(b"hello").hexdigest()
hashlib.blake2b(b"hello").hexdigest()
JavaScript(Web Crypto)
async function sha256(text) {
const buf = new TextEncoder().encode(text);
const hash = await crypto.subtle.digest("SHA-256", buf);
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, "0")).join("");
}
Node.js
const crypto = require("crypto");
crypto.createHash("sha256").update("hello").digest("hex");
Go
import "crypto/sha256"
import "encoding/hex"
hex.EncodeToString(sha256.Sum256([]byte("hello"))[:])
Rust
use sha2::{Sha256, Digest};
let result = Sha256::digest(b"hello");
println!("{:x}", result);
Bash
echo -n "hello" | shasum -a 256
echo -n "hello" | sha256sum # Linux
echo -n "hello" | openssl dgst -sha256
8. FAQ
Q1:MD5 完全不能用嗎? 不能用於安全場景(簽章、密碼、信任)。可用於純粹 cache key、HashMap、非安全 checksum。
Q2:SHA-256 永遠安全嗎? 量子電腦 Grover 演算法理論上可把 256 bit 安全強度降到 128 bit,仍足夠 2050 年前。
Q3:BLAKE3 為什麼還沒普及? 較新(2020),相容性還沒到 SHA-256 等級。新專案可考慮,跨平台需注意。
Q4:用 SHA-512 取代 SHA-256 有意義嗎? 64-bit 伺服器上 SHA-512 更快,但相容性較差。除非有 256 bit 安全強度需求,否則沿用 SHA-256。
Q5:bcrypt 跟 argon2 怎麼選? 新專案首選 argon2id;既有 bcrypt 系統可保留(cost factor 升到 12+)。
9. 實戰案例研究
案例 1:Flame 惡意程式偽造 Microsoft 證書
2012 年發現的 Flame 中東惡意程式利用 MD5 碰撞攻擊:
- 攻擊者找出兩個 MD5 相同的證書—— 一個合法 Microsoft Terminal Server license server 證書、一個假冒 Windows Update 簽章證書
- Microsoft 簽合法那個 → 攻擊者用假冒的偽造 Windows Update
- 數以萬計 Windows 自動下載「合法簽名」的惡意更新
事後 Microsoft 緊急在 2012 年 6 月發布 KB2718704 撤銷相關證書,並全面廢棄 MD5。
教訓:MD5 用在簽章 = 給攻擊者開後門。
案例 2:LinkedIn 2012 6.5 million 密碼洩漏
LinkedIn 2012 被攻擊洩出 6.5 million 帳號的 SHA-1 密碼 hash(無 salt)。攻擊者用 GPU 字典攻擊 6 天破解 90%。
更糟的是同樣 hash 在 2016 重新外洩,這次洩 1.65 億筆(4 年累積)。
修法(後續業界普遍):
- 立刻全 user 重設密碼
- 改用 bcrypt
- 密碼加 salt + pepper
- 強制 MFA
教訓:用快 hash + 無 salt 存密碼 = 等著被破。
案例 3:Git SHA-1 轉 SHA-256
2017 年 Google + 阿姆斯特丹大學 SHAttered 計畫公開 SHA-1 碰撞攻擊,成本約 11 萬美元。Git 用 SHA-1 當 commit ID 引起社群恐慌。
Git 團隊 2018-2021 漸進加入 SHA-256 支援:
- 2.29(2020):
--object-format=sha256新增 repo - 2.42(2023):SHA-256 / SHA-1 倉庫互通工具
- GitHub 2025 起新 repo 預設 SHA-256
移轉考量:
- 跨 server push 需配對相同 format
- CI/CD 取 commit hash 邏輯要更新
- third-party tool(GitHub Actions / GitLab CI)要支援
教訓:底層 hash 演算法的升級需數年漸進,不能等到全壞才動。
10. 結論 + 延伸閱讀
Hash 演算法的選擇不是「越強越好」,而是「對應場景」。一般 hash 用 SHA-256 或 BLAKE3、密碼存儲一律用 argon2id、HMAC 簽章用 SHA-256 + constant-time 比較。下次面對 hash 需求時,先問三件事:要不要碰撞抗性?要不要刻意慢?要不要可平行?答案出來演算法自然就定了。三條黃金法則:安全相關別碰 MD5/SHA-1、密碼用 argon2id 不要用 hash、比較簽章用 constant-time。
延伸閱讀: