iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Software Development

我是Java工程師,關於密碼學我想懂的不多系列 第 24 篇

Day23 - 對稱加密總結與安全避坑指南

  • 分享至 

  • xImage
  •  

前言

經過前二十一天的深入探討,我們從傳統的分組密碼(DES/3DES)、工作模式(ECB/CBC)、金鑰衍生(KDF/HKDF)、訊息認證碼(MAC/HMAC),一路演進至現代工程標準的 AEAD(AES-GCM / ChaCha20-Poly1305)。

在正式邁入非對稱加密(RSA、ECC、Diffie-Hellman)之前,本章將對對稱密碼學進行全面盤點,總結演進脈絡,並列出 Java JCA 開發中最常出現的 10 大致命工程坑點與防範指南。

一、 對稱加密演進地圖

https://ithelp.ithome.com.tw/upload/images/20261007/20128084pYnb45MUCH.png

對稱加密技術規格與使用場景比對

演算法 / 模式 機密性 (Confidentiality) 完整性認證 (Authenticity) 安全評級 現代工程應用建議
AES-ECB 弱 無 嚴禁使用 明文模式洩漏結構,僅能處理 1 個 Block 的極特殊情境。
AES-CBC 有 無 不推薦 缺少完整性保護,極易受 Padding Oracle 攻擊;舊系統過渡用。
AES-CBC + HMAC (EtM) 有 有 合格 (需極度小心) 手動組裝模式,工程細節繁瑣,僅在無 AEAD 硬體支援時使用。
AES-GCM 有 有 (GHASH) 黃金標準 現代系統預設選擇,硬體 AES-NI 加速,支援 AAD 附加資料。
ChaCha20-Poly1305 有 有 (Poly1305) 黃金標準 無硬體 AES 加速設備(如舊型 Mobile/IoT)的最佳替代方案。

二、 Java JCA 對稱加密 10 大工程陷阱與避坑指南

陷阱 1:誤用 AES/ECB/PKCS5Padding

  • 根因:Java 的 Cipher.getInstance("AES") 預設就是 AES/ECB/PKCS5Padding。ECB 模式將相同的明文區塊加密成相同的密文區塊,完全無法隱藏資料特徵(經典企鵝圖案)。
  • 避坑指南:程式碼中永遠明確指定完整演算法路徑,如 AES/GCM/NoPadding。

陷阱 2:AES-GCM 重用 Nonce (IV)

  • 根因:AES-GCM 內部採用 Counter (CTR) 模式與 GHASH 運算。若使用相同的 Key 與 Nonce 加密兩份不同資料,攻擊者可透過 XOR 運算還原明文,並直接推算出 GHASH 驗證金鑰,導致保密性與認證性全面崩潰。
  • 避坑指南:每次加密必須透過 SecureRandom 生成全新的 12-byte (96-bit) Nonce,絕不重複。

陷阱 3:混淆安全隨機數產生器(使用 java.util.Random)

  • 根因:java.util.Random 是線性同餘伪隨機數產生器(PRNG),其內部狀態可被輕鬆推算,算出的 IV 或 Key 完全可預測。
  • 避坑指南:密碼學相關的所有隨機數,**強制採用 java.security.SecureRandom**。

陷阱 4:金鑰重用且未做金鑰分離 (Key Separation)

  • 根因:在手動實作 EtM 時,直接拿同一把 Key 同時傳給 AES 加密與 HMAC 計算。這破壞了密碼學獨立性假設,可能產生跨演算法狀態洩漏。
  • 避坑指南:必須透過 HKDF (RFC 5869) 傳入不同的 context 標籤(info),衍生出獨立的 $K_{enc}$ 與 $K_{mac}$。

陷阱 5:MAC 標籤比對採用一般 Arrays.equals()

  • 根因:一般字串或陣列比對遇到第一個不匹配的 byte 就會提前中斷,這會產生微秒級的時間差異,攻擊者可利用時序攻擊 (Timing Attack) 逐步逐 byte 暴力破解出合法 Tag。
  • 避坑指南:強制採用常數時間比對函數 MessageDigest.isEqual()。

陷阱 6:加密時將敏感字串寫死在 String 物件中

  • 根因:Java 的 String 是 Immutable(不可變)且存在 String Pool 中, GC(垃圾回收)時間不確定,敏感 Key 或明文會在記憶體中停留極長時間,易遭 Heap Dump 竊取。
  • 避坑指南:敏感資料與金鑰盡量使用 byte[] 或 char[] 處理,使用完畢後立即以 Arrays.fill(keyBytes, (byte) 0) 抹除記憶體。

陷阱 7:在 PBE(基於密碼加密)中使用過低的工作因子 (Iteration Count)

  • 根因:人類設定的密碼熵極低。若使用 PBKDF2 時迭代次數過低(如舊教程寫的 1,000 次),駭客使用 GPU 能在幾秒內撞庫破解。
  • 避坑指南:PBKDF2 迭代次數至少設定在 600,000 次以上(符合 OWASP 現代建議),或直接採用更抗 GPU 的 Argon2id / scrypt。

陷阱 8:解密順序顛倒 (Decrypt-then-MAC)

  • 根因:在手動實作加密與認證時,先呼叫 Cipher.doFinal() 解密,解密失敗才檢查 MAC。這給了攻擊者傳送惡意密文誘發 Padding Oracle 的機會。
  • 避坑指南:嚴格恪守 Verify-then-Decrypt 原則:先驗證 MAC,完全確認無誤後才允許接觸解密引擎(AEAD 內部已自動完成此防護)。

陷阱 9:忽略了 AAD(Associated Data)防篡改需求

  • 根因:系統傳輸時,有些 Header 資料(如路由 ID、Protocol 版本、User ID)必須保持明文以便中間節點讀取,但開發者忘了保護其不被修改。
  • 避坑指南:使用 AES-GCM 的 cipher.updateAAD(aadBytes),將明文 Header 綁定至認證標籤中,確保資料未經授權無法被替換。

陷阱 10:使用已廢棄的弱密碼學套件

  • 根因:維護舊程式碼時,繼續沿用 DES、DESede (3DES)、RC4 或 Blowfish。
  • 避坑指南:全面停用 64-bit 區塊密碼與串流密碼,現代專案只允許使用 AES (128/256-bit) 或 ChaCha20。

三、 對稱加密的瓶頸

https://ithelp.ithome.com.tw/upload/images/20261007/20128084SLpkIJc9Hg.png


上一篇
Day22 - 金鑰衍生與 PBE 實戰
系列文
我是Java工程師,關於密碼學我想懂的不多 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言