演算法安全性比較表
演算法安全性比較表

什麼是雜湊演算法?

雜湊演算法(Hash Algorithm)是一種將任意長度的輸入資料轉換為固定長度輸出的數學函數。這個輸出被稱為「雜湊值」(Hash Value)或「摘要」(Digest)。

雜湊函數的三大特性

  1. 單向性(One-way):從輸入計算雜湊值很容易,但從雜湊值反推原始輸入在計算上不可行。
  2. 確定性(Deterministic):相同的輸入永遠產生相同的雜湊值。
  3. 雪崩效應(Avalanche Effect):輸入的微小變化會導致雜湊值產生巨大差異。

雪崩效應示範

輸入 1: "password"
SHA-256: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

輸入 2: "Password"(只改一個字母大小寫)
SHA-256: e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a

結果:完全不同的雜湊值
密碼雜湊最佳實踐
密碼雜湊最佳實踐

雜湊 vs 加密:核心差異

許多人混淆雜湊和加密,但它們的目的和特性完全不同:

特性 雜湊(Hash) 加密(Encryption)
可逆性 ❌ 不可逆(單向) ✅ 可逆(雙向)
輸出長度 固定長度 依輸入而變
密鑰 不需要密鑰 需要密鑰
主要用途 驗證完整性、密碼儲存 保護資料機密性
典型演算法 SHA-256, bcrypt AES, RSA
範例場景 檢查檔案是否被竄改 傳輸敏感資料

💡 重點理解

雜湊像是「數位指紋」,用來識別和驗證資料;加密像是「保險箱」,用來保護資料內容不被看見。密碼儲存應使用雜湊而非加密!

主流雜湊演算法介紹

1. MD5(Message-Digest Algorithm 5)

  • 輸出長度:128 位元(32 個十六進制字元)
  • 發布年份:1991 年
  • 安全狀態:❌ 已破解,不建議用於安全目的
  • 應用場景:檔案完整性檢查(非安全要求)

⚠️ MD5 存在嚴重的碰撞漏洞,攻擊者可以製造出相同雜湊值的不同檔案。僅適合用於非安全用途,如檔案校驗。

2. SHA-1(Secure Hash Algorithm 1)

  • 輸出長度:160 位元(40 個十六進制字元)
  • 發布年份:1995 年
  • 安全狀態:❌ 已棄用(2017年實現首次碰撞)
  • 應用場景:Git 版本控制(歷史原因)

3. SHA-256(SHA-2 家族)

  • 輸出長度:256 位元(64 個十六進制字元)
  • 發布年份:2001 年
  • 安全狀態:✅ 目前安全,廣泛使用
  • 應用場景:SSL/TLS 憑證、區塊鏈、數位簽章
範例:
輸入: "hello"
SHA-256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

4. SHA-512(SHA-2 家族)

  • 輸出長度:512 位元(128 個十六進制字元)
  • 安全狀態:✅ 目前安全,比 SHA-256 更強
  • 應用場景:高安全需求的應用

5. bcrypt

  • 類型:密碼雜湊專用函數
  • 發布年份:1999 年
  • 核心特性:內建加鹽、可調整計算成本
  • 安全狀態:✅ 專為密碼設計,高度安全
  • 應用場景:使用者密碼儲存
bcrypt 雜湊範例:
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
│  │  │                  鹽值(22字元)    │ 雜湊值(31字元)
│  │  └─ 成本因子(工作因子)= 10 → 2^10 次迭代
│  └─ bcrypt 版本
└─ 演算法識別碼

6. Argon2

  • 類型:現代密碼雜湊函數
  • 發布年份:2015 年(密碼雜湊競賽冠軍)
  • 核心特性:記憶體困難、抗 ASIC 攻擊
  • 安全狀態:✅ 目前最先進的密碼雜湊演算法
  • 應用場景:新專案的密碼儲存首選

演算法選擇指南

用途 推薦演算法 備註
密碼儲存 Argon2 > bcrypt > scrypt 永遠不要用 MD5/SHA-256
資料完整性 SHA-256, SHA-512 快速、標準化
數位簽章 SHA-256, SHA-512 配合 RSA/ECDSA
檔案校驗 SHA-256(推薦), MD5(低安全) 非安全場合可用 MD5
HMAC 驗證 HMAC-SHA-256 API 驗證、訊息認證

實際應用場景

1. 密碼儲存

這是雜湊最常見的應用。系統不應儲存明文密碼,而是儲存密碼的雜湊值:

使用者註冊:
  1. 使用者輸入密碼: "MyP@ssw0rd"
  2. 系統加鹽並雜湊: bcrypt("MyP@ssw0rd" + salt)
  3. 儲存雜湊值到資料庫

使用者登入:
  1. 使用者輸入密碼: "MyP@ssw0rd"
  2. 從資料庫取得儲存的雜湊值
  3. 使用相同方法雜湊輸入密碼
  4. 比較兩個雜湊值是否一致

2. 資料完整性驗證

確保檔案或資料在傳輸過程中未被竄改:

檔案下載驗證:
  官方網站提供: ubuntu-20.04.iso (SHA-256: a1b2c3d4...)
  下載後計算: sha256sum ubuntu-20.04.iso
  比對雜湊值 → 確認檔案完整

3. 數位簽章

結合雜湊和非對稱加密,驗證文件來源和完整性:

簽署流程:
  1. 計算文件雜湊值: SHA-256(document)
  2. 使用私鑰加密雜湊值: RSA_encrypt(hash, private_key)
  3. 附加簽章到文件

驗證流程:
  1. 使用公鑰解密簽章: RSA_decrypt(signature, public_key)
  2. 計算文件雜湊值: SHA-256(document)
  3. 比對兩個雜湊值

4. HMAC(Hash-based Message Authentication Code)

結合雜湊和密鑰,用於訊息認證:

API 請求簽署:
  1. 準備請求資料: {"user_id": 123, "action": "transfer"}
  2. 計算 HMAC: HMAC-SHA-256(data, secret_key)
  3. 附加 HMAC 到請求標頭
  4. 伺服器驗證 HMAC 確認請求未被竄改

安全性威脅與防禦

1. 碰撞攻擊(Collision Attack)

找到兩個不同的輸入產生相同的雜湊值。MD5 和 SHA-1 已被證明存在實用的碰撞攻擊。

防禦方法:使用更強的演算法(SHA-256、SHA-512)。

2. 彩虹表攻擊(Rainbow Table Attack)

預先計算大量密碼的雜湊值並建立查詢表,快速破解未加鹽的密碼雜湊。

彩虹表範例:
password     → 5f4dcc3b5aa765d61d8327deb882cf99 (MD5)
123456       → e10adc3949ba59abbe56e057f20f883e (MD5)
qwerty       → d8578edf8458ce06fbc5bb76a58c5ca4 (MD5)

攻擊者只需查表即可反查密碼

防禦方法:加鹽(Salting)- 在密碼後附加隨機字串再雜湊。

3. 暴力破解(Brute Force Attack)

系統化地嘗試所有可能的密碼組合。現代 GPU 可以每秒嘗試數十億次 MD5/SHA 雜湊。

防禦方法:使用慢速雜湊函數(bcrypt、Argon2)增加計算成本。

加鹽技術深入解析

不加鹽(危險):
使用者 A 密碼: "password" → Hash: 5f4dcc3b...
使用者 B 密碼: "password" → Hash: 5f4dcc3b...(相同!)
→ 攻擊者破解一個,所有相同密碼都被破解

加鹽(安全):
使用者 A:
  密碼: "password"
  鹽值: "a8b3c2d1"
  雜湊: bcrypt("password" + "a8b3c2d1") → $2a$10$a8b3c2d1...

使用者 B:
  密碼: "password"
  鹽值: "x9y7z5w3"
  雜湊: bcrypt("password" + "x9y7z5w3") → $2a$10$x9y7z5w3...

→ 即使密碼相同,雜湊值完全不同

程式實作範例

JavaScript(Node.js)實作

// 使用內建 crypto 模組
const crypto = require('crypto');

// 1. SHA-256 雜湊
function sha256Hash(input) {
    return crypto.createHash('sha256')
                 .update(input)
                 .digest('hex');
}

console.log(sha256Hash('password'));
// 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

// 2. HMAC-SHA-256
function hmacSha256(message, secret) {
    return crypto.createHmac('sha256', secret)
                 .update(message)
                 .digest('hex');
}

const signature = hmacSha256('API request data', 'my-secret-key');
console.log(signature);

// 3. bcrypt 密碼雜湊(需安裝 bcrypt 套件)
const bcrypt = require('bcrypt');

async function hashPassword(password) {
    const saltRounds = 10;  // 成本因子,越高越安全但越慢
    const hash = await bcrypt.hash(password, saltRounds);
    return hash;
}

async function verifyPassword(password, hash) {
    const match = await bcrypt.compare(password, hash);
    return match;
}

// 使用範例
(async () => {
    const password = 'MySecurePassword123';
    const hash = await hashPassword(password);
    console.log('雜湊值:', hash);

    const isValid = await verifyPassword('MySecurePassword123', hash);
    console.log('密碼正確:', isValid);  // true

    const isInvalid = await verifyPassword('WrongPassword', hash);
    console.log('錯誤密碼:', isInvalid);  // false
})();

Python 實作

# 使用內建 hashlib 模組
import hashlib
import hmac

# 1. SHA-256 雜湊
def sha256_hash(input_string):
    return hashlib.sha256(input_string.encode()).hexdigest()

print(sha256_hash('password'))
# 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

# 2. HMAC-SHA-256
def hmac_sha256(message, secret):
    return hmac.new(
        secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

signature = hmac_sha256('API request data', 'my-secret-key')
print(signature)

# 3. bcrypt 密碼雜湊(需安裝 bcrypt 套件)
import bcrypt

def hash_password(password):
    # 生成鹽值並雜湊
    salt = bcrypt.gensalt(rounds=10)  # rounds = 成本因子
    hashed = bcrypt.hashpw(password.encode(), salt)
    return hashed.decode()

def verify_password(password, hashed):
    return bcrypt.checkpw(password.encode(), hashed.encode())

# 使用範例
password = 'MySecurePassword123'
hashed = hash_password(password)
print(f'雜湊值: {hashed}')

is_valid = verify_password('MySecurePassword123', hashed)
print(f'密碼正確: {is_valid}')  # True

is_invalid = verify_password('WrongPassword', hashed)
print(f'錯誤密碼: {is_invalid}')  # False

PHP 實作

<?php
// 1. SHA-256 雜湊
function sha256Hash($input) {
    return hash('sha256', $input);
}

echo sha256Hash('password');
// 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

// 2. HMAC-SHA-256
function hmacSha256($message, $secret) {
    return hash_hmac('sha256', $message, $secret);
}

$signature = hmacSha256('API request data', 'my-secret-key');
echo $signature;

// 3. bcrypt 密碼雜湊(PHP 5.5+ 內建)
function hashPassword($password) {
    // PASSWORD_BCRYPT 使用 bcrypt 演算法
    // cost 參數控制計算成本(預設 10)
    return password_hash($password, PASSWORD_BCRYPT, ['cost' => 10]);
}

function verifyPassword($password, $hash) {
    return password_verify($password, $hash);
}

// 使用範例
$password = 'MySecurePassword123';
$hash = hashPassword($password);
echo "雜湊值: $hash\n";

$isValid = verifyPassword('MySecurePassword123', $hash);
echo "密碼正確: " . ($isValid ? 'true' : 'false') . "\n";  // true

$isInvalid = verifyPassword('WrongPassword', $hash);
echo "錯誤密碼: " . ($isInvalid ? 'true' : 'false') . "\n";  // false
?>

密碼儲存最佳實踐

✅ 應該做的事

  1. 使用專用密碼雜湊函數:選擇 Argon2、bcrypt 或 scrypt,而非通用雜湊函數。
  2. 自動加鹽:現代密碼雜湊函數內建隨機鹽值生成。
  3. 調整成本因子:根據硬體性能調整,目標是雜湊時間約 250-500 毫秒。
  4. 定期更新演算法:隨著硬體進步,提高成本因子或遷移到更強演算法。
  5. 使用驗證函數:使用 bcrypt.compare() 而非手動比對雜湊值。

❌ 不應該做的事

  1. 不要用快速雜湊:MD5、SHA-256 太快,容易被暴力破解。
  2. 不要自己實作加密:使用經過充分測試的函式庫。
  3. 不要儲存明文密碼:即使是臨時測試環境也不行。
  4. 不要用固定鹽值:每個密碼都應該有唯一的隨機鹽值。
  5. 不要限制密碼長度:不要將密碼截斷到特定長度。

成本因子調整指南

bcrypt 成本因子影響:
Rounds = 10 → 2^10 = 1,024 次迭代 → ~50ms
Rounds = 12 → 2^12 = 4,096 次迭代 → ~200ms(建議)
Rounds = 14 → 2^14 = 16,384 次迭代 → ~800ms

選擇原則:
- 使用者登入可接受的延遲(建議 < 1 秒)
- 定期評估硬體進步並提高成本因子
- 平衡安全性與使用者體驗

完整密碼處理流程

使用者註冊:
  1. 驗證密碼強度(長度、複雜度)
  2. 使用 bcrypt/Argon2 雜湊密碼
  3. 儲存雜湊值到資料庫
  4. 記錄使用的演算法和成本因子

使用者登入:
  1. 接收使用者輸入
  2. 從資料庫查詢雜湊值
  3. 使用相同演算法驗證
  4. 如果成功且演算法過舊,重新雜湊並更新
  5. 實施登入嘗試次數限制

密碼重設:
  1. 生成隨機 token(使用安全隨機函數)
  2. 雜湊 token 並設定過期時間
  3. 發送 token 到使用者信箱
  4. 驗證 token 並允許設定新密碼
  5. 使雜湊後的新密碼,使所有舊 session 失效

結論與建議

雜湊演算法是現代資訊安全的基石。正確選擇和使用雜湊演算法,能有效保護使用者資料和系統安全。

核心建議總結

  • 密碼儲存:優先選擇 Argon2,次選 bcrypt
  • 資料完整性:使用 SHA-256 或 SHA-512
  • 訊息認證:使用 HMAC-SHA-256
  • 避免:MD5 和 SHA-1 用於安全用途
  • 持續學習:密碼學領域不斷演進,定期更新知識