密碼學圈共識:「加密不等於認證」。無數開發者把加密後的Cookie/Token直接解密就信任,導致篡改攻擊、重放攻擊、偽造身份層出不窮。本文剖析兩者本質區別、常見誤用模式、工程級正確方案。
核心定義:CIA三角視角
| 屬性 | 加密 | 認證 |
| 提供 | 機密性 | 完整性 + 真實性(來源驗證) |
| 不提供 | 完整性/真實性 | 機密性 |
| 被篡改後 | 解密出垃圾數據,但不會報錯 | 驗證失敗,拒絕處理 |
| 惡意第三方 | 可構造合法密文發送 | 無密鑰無法構造合法標簽 |
典型誤用模式
# 錯誤示範:僅加密,解密後盲目信任
cookie = encrypt(user_id + role + expiry, key)
# 攻擊者截獲 cookie → 修改密文塊(如CBC翻轉攻擊) → 解密後 role 變 admin → 權限提升
# 正確模式:加密 + 認證 (Encrypt-then-MAC / AEAD)
cookie = encrypt(user_data, enc_key)
tag = HMAC(cookie, mac_key) # 或 AES-GCM/ChaCha20-Poly1305 一體化
# 驗證 tag 通過後才解密使用
工程級正確方案
- 優先使用AEAD算法(認證加密關聯數據):
• AES-GCM / ChaCha20-Poly1305 — 一次操作同時提供機密性+完整性+真實性
• 庫支持:libsodium / OpenSSL 3.0+ / Go crypto / Java 11+ / .NET Core
- 若必須分離(歷史系統): 採用 Encrypt-then-MAC 模式
• 先加密,再對密文計算HMAC-SHA256
• 驗證時:先驗證MAC(恒定時間比較),通過才解密
• 密鑰分離:EncKey = HKDF(master, "enc"), MacKey = HKDF(master, "mac")
- 關鍵非功能性要求:
• Nonce/IV 唯一性:同一密鑰下絕不重複(計數器/隨機96位/單調遞增)
• 關聯數據(AAD)綁定上下文:用戶ID/會話ID/接口版本號,防止跨上下文重放
• 恒定時間比較防側信道:hmac.compare_digest() / MessageDigest.isEqual()
常見場景對照表
| 場景 | 錯誤做法 | 正確做法 |
| Session Cookie | AES-CBC加密,解密後直接信任 | AES-GCM / JWT簽名(JWS) + 短過期 + HttpOnly Secure SameSite |
| API簽名 | 參數拼接MD5(無密鑰/弱密鑰) | HMAC-SHA256 / EdDSA簽名,含Timestamp/Nonce防重放 |
| 文件完整性 | 存MD5/SHA1摘要 | HMAC-SHA256 / 簽名(Ed25519/RSA-PSS),密鑰受保護 |
| 密碼存儲 | 加密存儲(可逆) | 不可逆哈希:Argon2id / bcrypt / scrypt / PBKDF2,高記憶體/計算成本 |
給架構師的檢查清單
- 所有「解密後直接使用」的代碼路徑是否有認證驗證?
- 是否存在「加密即信任」的隱性假設?
- 密鑰管理:生成/分發/輪換/銷毀/審計/ HSM保護?
- 算法選型:是否仍在用MD5/SHA1/DES/3DES/RC4/ECB模式?
- 依賴庫版本:是否有已知CVE(如OpenSSL Heartbleed/CCS Injection)?
記住:加密保護秘密,認證保護真相。 缺一不可,順序不反(Encrypt-then-MAC),算法用AEAD,密鑰上HSM,Nonce不重用,比較用恒定時間。這才是密碼學工程化的正確姿勢。
copyright ©
萬盛學電腦網 all rights reserved