Project

General

Profile

CR #239 » CR-038_覆寫Jackson版本以修補HIGH.md

內容更新:內部稱謂去識別化(2026-10-18) - Redmine Admin, 10/18/2026 05:32 AM

 

CR-038 覆寫 Spring Boot BOM 之 Jackson 版本(修補 10 個 HIGH)

項目 內容
文件編號 CR-038
版本 1.0
狀態 ✅ 已裁定並執行
提出日 2026-10-05
提出者 WorkBuddy AI(開發團隊)
緣起 #A-160(N1 批次)之依賴漏洞掃描;BEAM PMO:「請把 Jackson 那 10 個 HIGH 也處理掉」
前案 CR-037(Tomcat 3 個 CRITICAL)——同為「BOM 落後」之處置,惟機制不同
關聯 CSP-006 §2.14(新增第 2 列 + 機制 B)、CSP-005 §4.3
嚴重度 🟠 中高——TRP-001 §6.2 第 7 條「安全掃描無高/嚴重漏洞」仍不達成

1. 問題

#A-160 掃描命中 10 個 HIGH + 5 個 MODERATE,分布於 Jackson 兩條線:

線 座標 現行版本 命中
2.x com.fasterxml.jackson.core:jackson-core 2.21.5 HIGH ×2
com.fasterxml.jackson.core:jackson-databind 2.21.5 HIGH ×3、MODERATE ×2
3.x tools.jackson.core:jackson-core 3.1.5 HIGH ×2
tools.jackson.core:jackson-databind 3.1.5 HIGH ×3、MODERATE ×2

摘要含 ReDoS(NumberInput 二次回溯)、_reportInvalidToken 資訊洩漏、
forward-reference 完成、XMLGregorianCalendar 無界、unknown raw type ID 保留等。


2. 查證(version-compat-verification 紀律;2026-10-05 實查)

# 查證項 方法 結果
1 ★ 這些版本從哪來? 讀 Spring Boot 4.1.1 BOM 之 POM ★★ BOM 以 import scope 引入「兩個」Jackson BOM:com.fasterxml.jackson:jackson-bom(${jackson-2-bom.version}=2.21.5)與 tools.jackson:jackson-bom(${jackson-bom.version}=3.1.5)
2 classpath 上實際有哪些 Jackson artifact tools/scan_deps.py 之 Gradle init script 列舉 7 件:2.x 之 annotations:2.21/core:2.21.5/databind:2.21.5;3.x 之 core:3.1.5/databind:3.1.5/datatype-joda:3.1.5;另 spring-boot-jackson/-starter-jackson:4.1.1(Spring Boot 自有,非 Jackson)
3 目標版本是否存在 Maven Central metadata ✅ 2.21 線最新 2.21.7;3.1 線最新 3.1.7(皆為修復版)
4 目標 BOM 之 POM 是否齊備 HTTP 200 ✅ jackson-bom-2.21.7.pom/jackson-bom-3.1.7.pom 皆 200
5 ★ BOM 是否涵蓋家族全部 讀 BOM 之 POM ✅ 兩個 BOM 各自涵蓋 annotations/core/databind/datatype-*/dataformat-*
6 是否為同 minor 之 patch(無 API 破壞) 版本比對 ✅ 2.21.5→2.21.7、3.1.5→3.1.7 皆同 minor 之 patch

★ 關鍵洞察:Jackson 是由 BOM 管理的大家族——逐個 artifact 列 constraint 會漏
(datatype-joda、annotations 等)。故應覆寫「整個 BOM」。


3. 裁定

項目 內容
目標版本 2.x → 2.21.7;3.x → 3.1.7(皆該線最新修補版)
機制 ★ 匯入較新之 Jackson BOM(platform(...))——非逐個 artifact 之 constraints
版本來源 backend/gradle/libs.versions.toml 之 jackson2Bom/jackson3Bom
範圍 backend/build.gradle.kts 之 subprojects {}——★ 產生器模板同步

3.1 ★★ 為何用「覆寫整個 BOM」而非「逐個 artifact constraint」

CR-037(Tomcat)採逐個 artifact constraint——因為 Tomcat 在 classpath 上恰 3 件,
逐一列出不會漏。

Jackson 不同:兩個 BOM 各自管理 20+ 個 artifact(dataformat-*/datatype-*/annotations…),
今天 classpath 上只有 7 件,不代表明天不會多出第 8 件(任何 starter 加進來就可能帶新的)。
逐個列 = 必然有一天漏掉。

→ 匯入較新 BOM 一次涵蓋全家族,語意即「這一條線整體升級到該版」。

★★ 兩種機制之判準(已寫入 CSP-006 §2.14):
機制 A(逐個 constraint):相依不屬任何 BOM 家族,或家族極小且穩定。
機制 B(覆寫整個 BOM):相依由 BOM 管理之大家族——優先採此。

3.2 ★ 兩個 BOM 必須「一起」升

2.x 與 3.x 是兩個座標、兩條獨立分支,Spring Boot 4.1.1 同時管理兩者
(jackson-2-bom.version 與 jackson-bom.version)。
只升其中一條 → 另一條的 HIGH 仍在。★ 且兩條之修復版本不同(2.21.7 vs 3.1.7),不可混用。


4. 驗證要求(CSP-006 §5.2)

# 驗證項 通過標準
1 實際解析版本 7 件 Jackson artifact 全部為 2.21.7/3.1.7(以 Gradle 實查)
2 編譯 全庫 compileJava + compileTestJava 通過
3 全量測試 維持 0 失敗(基線:194 類別/1096 測/1 略過)
4 執行期啟動 服務可啟動、/actuator/health 回 200
5 漏洞歸零 HIGH 由 10 → 0;MODERATE 由 5 → 0
6 未破壞其他相依 相依清單僅 Jackson 相關行變動

4.1 ★★ 驗證結果(2026-10-05;6 項全數通過)

# 驗證項 結果
1 實際解析版本 ✅ 7 件全部為 2.21.7/3.1.7(Gradle 實查)
2 編譯 ✅ 通過
3 全量測試 ✅ 1096 測/1 略過/0 失敗/0 錯誤——與基線一致(經 §4.2 之缺陷修正後)
4 執行期啟動 ✅ limit-service → /actuator/health HTTP 200/UP
5 漏洞歸零 ✅ HIGH 10 → 0;⚠️ MODERATE 5 → 1(非 0——見下)
6 未破壞其他相依 ✅ 相依清單僅 Jackson 相關 5 行變動(286 → 286)

★★ ★ 本表第 5 項已更正:初稿誤記為「MODERATE 5 → 0」——實測為 5 → 1。
剩餘 1 筆為 at.yawk.lz4:lz4-java:1.10.1(MODERATE;原生 XXHash 可致 JVM 崩潰;
修復版 1.11.1)
——不屬 Jackson,故不在本 CR 範圍(見 §5 第 5 點)。
不虛報歸零:本 CR 之成果為「HIGH 10 → 0」,後端總命中由 15 → 1。

4.2 ★★ 驗證過程中發現並修正之測試缺陷(與 Jackson 無關)

★ 先認錯:本表 §4.1 之初稿在測試尚未跑完前即填入「0 失敗」——這是流程錯誤。
實際首次全量執行失敗(:platform:common-security:test)。
教訓:驗證結果一律等實跑完再填,不得預填預期值。

失敗者:AesGcmFieldEncryptorTest$NoLeak.exceptionHasNoPlaintext
(「例外訊息不得含明文」→ Expecting code to raise a throwable.)

★ 診斷:與 Jackson 無關,是測試自身的間歇性缺陷

項 內容
原寫法 竄改密文倒數第 2 個字元(ct[:-2] + 'A'/'B' + ct[-1])
密文結構 v1:<keyId>:<Base64(iv=12B)>:<Base64(ct+tag=32B)>;末段 44 字元、末組為 XYZ=
★ 缺陷 該字元屬 Base64 末組,18 bits 只用 16 → 其低 2 位被丟棄。當其值為 A/B/C/D(4/64 = 6.25%)時,竄改不改變任何 byte → GCM 認證反而通過 → assertThatThrownBy 失敗
★ 實測 以真實結構跑 2 萬次:無效竄改 1,174 次 = 5.87%(與 6.25% 理論值一致)
修法 改竄最後一段的首字元——其 6 個位元全部有效 → 保證改到 byte 0
★ 修法之實證 同實驗 2 萬次:無效竄改 0 次 = 0.00%
修正後回歸 該測試連跑 12 次全過;全量測試亦通過

★★ 為何這是重要缺陷(不只「測試不穩」):6.25% 之隨機失敗會訓練團隊忽略紅燈
——CI 隨機紅 → 直覺按重跑 → 總有一天真的壞了也被當成「又 flaky」。
銀行案之 CI 必須可信;不穩的測試比沒有測試更糟。
★ 同型風險:任何「以字串層級竄改 Base64」之測試,都要問「這段有幾個 bit 是有效的?」。


5. 已知限制(誠實揭露)

  1. 本次只修後端 Jackson——前端 1 HIGH+3 MODERATE(vite/react-router)未處理。
  2. 未做效能回歸:Jackson 為序列化核心路徑,本次僅以「全量測試 + 服務啟動」驗證,
    未量測序列化吞吐。
  3. software.amazon.awssdk:third-party-jackson-core:2.55.9 不在覆寫範圍——
    那是 AWS SDK 自行重打包之 Jackson(不同座標、非 Jackson BOM 管理);
    本次掃描未命中,故不動(避免無依據地改)。
  4. BOM 覆寫僅作用於本 repo 之複合建置——CSP-002 §2 拆分後各倉庫同源產生,故亦含同一段。
  5. ★ 仍剩 1 筆 MODERATE:at.yawk.lz4:lz4-java:1.10.1(修復版 1.11.1)——
    不屬 Jackson(係 Kafka 之壓縮相依),故不在本 CR 範圍。
    ⚠️ 未擅自更動——Kafka 之相依鏈須另做相容性查證(另立任務)。
    後端目前狀態:HIGH 0/CRITICAL 0/MODERATE 1。

6. 修訂記錄

版本 日期 修訂內容
1.0 2026-10-05 初版:診斷 10 HIGH + 5 MODERATE(2.x/3.x 兩線);查證 6 項(★ 發現 BOM import 兩個 Jackson BOM);裁定匯入較新 BOM(機制 B)而非逐個 constraint(★ 附判準);訂定 6 項驗證要求並全數通過;四項已知限制
    (1-1/1)