102 lines
9.1 KiB
Markdown
102 lines
9.1 KiB
Markdown
---
|
||
title: blog-topic / archunit-jackson-default-typing-cve-2019-14379-block-2026-05-29
|
||
source_type: blog-topic
|
||
status: raw
|
||
related_branches: [feature-boundary-validation-mapping-contract]
|
||
related_projects: [ca-tmpl]
|
||
tags: [blog-topic, ca-tmpl, archunit, jackson, security, cve, fitness-function, polymorphic-deserialization]
|
||
created: 2026-05-29
|
||
status_label: ready-for-canonical
|
||
target_audience: backend-engineer
|
||
inspiration_url:
|
||
archive_url:
|
||
---
|
||
|
||
# blog-topic: archunit-jackson-default-typing-cve-2019-14379-block-2026-05-29
|
||
|
||
> Layer: `raw/blog-topics/` — 채용공고가 아닌 작업·학습·트러블슈팅에서 나온 블로그 글감 원석. canonical 정제 전 raw 후보이며, `wiki/blog/` 직접 생성 근거가 아니다.
|
||
|
||
## Parent / 부모
|
||
|
||
- [[raw/branch-notes/feature-boundary-validation-mapping-contract]] — B5 결정 + Claims to Verify 의 두 행 `actually-implemented` 승급. 본 글감은 그 enforcement 패스의 보안 측면 단독 추출.
|
||
|
||
## 트리거 / Trigger
|
||
|
||
- 트리거 유형: `branch-work`
|
||
- 트리거 날짜: 2026-05-29
|
||
- 트리거 연결 노트: [[raw/branch-notes/feature-boundary-validation-mapping-contract]] — 1차 enforcement 패스에서 `no_jackson_laissez_faire_subtype_validator` + `no_jackson_enable_default_typing_call` 두 ArchUnit 규칙 + `DefaultTypingFixture` violations-as-data 테스트로 CVE-2019-14379 의 코드 진입점을 정적으로 차단한 작업.
|
||
|
||
## 글감 / Topic seed
|
||
|
||
- 한 문장 요지: Jackson polymorphic deserialization 의 RCE 게이트 (`ObjectMapper.enableDefaultTyping()` / `activateDefaultTyping(LaissezFaireSubTypeValidator)`) 는 *런타임 dependency check 가 아니라 컴파일/테스트 단계의 fitness function* 으로 막아야 안전하다 — 한번 머지된 뒤에는 production 트래픽으로 RCE 가 터지는 게 검출 시점이므로 너무 늦다.
|
||
- 떠오른 계기: feature-boundary-validation-mapping-contract B5 결정의 enforcement 단계. CVE 자체의 발견 (2019) 과 Jackson 2.10 의 `@Deprecated` 조치 (2019-09) 가 있었음에도, *우리 코드가 호출하지 않는다* 는 사실은 매 PR 마다 사람이 보장해야 하는 규약이었다. 이걸 ArchUnit fitness function 으로 commit 으로 박은 사례.
|
||
- 예상 제목 후보:
|
||
- CVE-2019-14379 의 호출 경로를 ArchUnit 으로 정적 봉쇄하기
|
||
- "Jackson 을 안전하게 쓴다" 를 컨벤션이 아닌 fitness function 으로 박는 방법
|
||
- `enableDefaultTyping()` 한 줄이 RCE 가 되는 이유와 정적 차단
|
||
|
||
## 핵심 주장 후보 / Claim candidates
|
||
|
||
- 사실 후보:
|
||
- CVE-2019-14379 의 RCE 경로는 `ObjectMapper.enableDefaultTyping()` 활성화 + `ehcache` 같은 gadget class 가 classpath 에 있는 조건 — 근거: NVD CVE-2019-14379 (CVSS 9.8), Jackson 보안 가이드 `enableDefaultTyping` 의 `@Deprecated since 2.10` 표기.
|
||
- Jackson 2.10 의 공식 대체 API 는 `activateDefaultTyping(PolymorphicTypeValidator)` 이며, allowlist 구현체 `BasicPolymorphicTypeValidator` 또는 `@JsonTypeInfo(use = NAME) + @JsonSubTypes` 명시가 정식 — 근거: `raw/official-docs/schema-jackson-polymorphic-deserialization.md#JACK-POLY-C1..C5`.
|
||
- `LaissezFaireSubTypeValidator` 는 *모든 subtype 허용* 의 명시적 anti-allowlist — 클래스 이름 그 자체가 "보안 검증 없음" 의 표지 — 근거: `JACK-POLY-C2`.
|
||
- ca-tmpl 의 적용: `src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java` 에 두 규칙 추가 — `no_jackson_laissez_faire_subtype_validator` (클래스 참조 차단), `no_jackson_enable_default_typing_call` (메서드 호출 차단). 위반 fixture 는 `violations/boundary/DefaultTypingFixture.java`.
|
||
- 규칙 두 개를 분리한 이유: `LaissezFaireSubTypeValidator` *없이* `enableDefaultTyping()` 만 호출해도 (`ObjectMapper.DefaultTyping.NON_FINAL` 등 deprecated overload) 위험. 호출 차단과 import 차단이 *독립적인 진입점* 이므로 둘 다 닫아야 한다.
|
||
- 경험 후보:
|
||
- ArchUnit DSL 의 `callMethodWhere(target(name(...)))` 패턴은 호출자 의도와 무관하게 *메서드 이름* 으로 catch. `enableDefaultTyping` 이라는 메서드 이름이 ObjectMapper 외부에 존재할 가능성이 거의 0 이므로 owner 필터를 생략해도 false positive 없음 — 단순 규칙이 충분.
|
||
- violations-as-data fixture 는 `DefaultTypingFixture.unsafe()` 한 메서드로 두 규칙을 동시에 catch (호출 + 참조). 한 fixture 가 *서로 다른 규칙 두 개를 동시에 검증* 하는 케이스 — 규칙별 1:1 fixture 가 아니어도 됨.
|
||
- `app-bootstrap` 의 test classpath 에 Jackson 이 없어서 컴파일 실패 → `testImplementation 'org.springframework.boot:spring-boot-starter-json'` 추가. *fitness function 자체에 의존성을 끌어들이는 cost* 가 있음을 의식해야 한다.
|
||
- 의견 / 해석 후보:
|
||
- 라이브러리 *버전* 차단 (jackson-databind ≥ 2.10) 은 supply-chain branch 의 책임이지만, *코드 사용 차단* (deprecated API 호출 금지) 은 boundary contract 의 책임. 두 가지를 같은 PR 에서 묶으면 책임 경계가 흐려진다.
|
||
- "CVE 가 알려진 후에는 사람이 review 로 막으면 된다" 는 흔한 반론은 *시간 경과에 따른 attention decay* 를 무시한다. 5년 뒤 합류한 신입이 PR review 할 때 `enableDefaultTyping` 이 안전한지 즉시 판단하기 어렵다 — fitness function 은 *지식 보존 비용* 의 외부화.
|
||
- Jackson 2.15 의 sealed type 자동 인식 같은 *조용한 행동 변화* 가 들어와도, 본 규칙은 호출 자체를 차단하므로 회귀 없음 — Jackson 의 mitigation 진화를 기다리는 대신 *진입점 자체를 봉쇄* 하는 전략의 정당화.
|
||
|
||
## Outline seed
|
||
|
||
1. CVE-2019-14379 의 한 줄 — `enableDefaultTyping()` + ehcache gadget 으로 RCE (CVSS 9.8).
|
||
2. Jackson 의 공식 대응 — 2.10 `@Deprecated` + `PolymorphicTypeValidator` + `BasicPolymorphicTypeValidator` allowlist.
|
||
3. 하지만 *우리 코드가 호출하지 않는다* 는 사실의 유지비용 — review fatigue, 시간 경과, 신입 합류.
|
||
4. fitness function 으로의 외부화 — ArchUnit 규칙 두 개 (`callMethodWhere` + `dependOnClassesThat`) 의 의도와 분리 이유.
|
||
5. violations-as-data 로 *규칙이 실제로 catch 하는지* 박기 — `DefaultTypingFixture` 한 메서드가 두 규칙을 동시에 검증.
|
||
6. fitness function 의 비용 — `spring-boot-starter-json` 을 test classpath 에 끌어들임.
|
||
7. 보안 책임의 경계 — *코드 사용 차단* (boundary contract) vs *버전 차단* (supply-chain) 의 분리.
|
||
8. 정리 — CVE 차단은 *지식 보존 비용* 의 코드화. fitness function 이 review 의 검토 부담을 commit 으로 이전한다.
|
||
|
||
## Canonical 전환 후보 / Canonical extraction candidates
|
||
|
||
- `wiki/projects/ca-tmpl/archunit-jackson-cve-block.md` 후보:
|
||
- 실제 두 규칙 + `DefaultTypingFixture` 의 코드 발췌.
|
||
- `testImplementation 'spring-boot-starter-json'` 추가의 비용.
|
||
- violations-as-data 1 fixture × 2 negative test 패턴.
|
||
- `wiki/concepts/fitness-function-for-known-cve.md` 후보:
|
||
- "*우리 코드가 호출하지 않는다*" 를 review 로 유지하는 비용 분석.
|
||
- 코드 사용 차단 vs 버전 차단의 책임 경계.
|
||
- 라이브러리 mitigation 진화와 *진입점 차단* 전략의 trade-off.
|
||
- 필요한 추가 검증:
|
||
- `BasicPolymorphicTypeValidator` 사용을 *권장* 하는 메시지를 ArchUnit 위반 메시지에 포함할 가치가 있는지 — false-positive 시 개발자가 즉시 대안을 알 수 있게.
|
||
- sealed `Command` 타입 도입 시 본 규칙이 `@JsonTypeInfo` 명시 패턴과 충돌하지 않는지 (충돌 없음 가설 — 검증은 future use case 에서).
|
||
|
||
## Sources / 근거 후보
|
||
|
||
- [[raw/branch-notes/feature-boundary-validation-mapping-contract]] — B5 결정 + 1차 enforcement 패스 결과.
|
||
- [[raw/official-docs/schema-jackson-polymorphic-deserialization]] — `JACK-POLY-C1..C5` (CVE, deprecated API, allowlist 표준).
|
||
- [[raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28]] — violations-as-data 메타 패턴. 본 글감은 그 패턴의 *보안* 특화 사례.
|
||
- [[raw/branch-notes/feature-architecture-enforcement-rules]] — 같은 fitness-function 자체 검증 라인.
|
||
|
||
## 미해결 / Unknown
|
||
|
||
- 아직 확인해야 할 사실: violation message에 `BasicPolymorphicTypeValidator` 대안을 포함할지 여부.
|
||
- 과장하면 안 되는 부분: ArchUnit rule은 ca-tmpl 코드의 특정 호출/참조를 차단하는 것이며, Jackson RCE 일반 위험을 모두 제거한다고 쓰지 않는다.
|
||
|
||
## Related / 관련
|
||
|
||
- 관련 branch: [[raw/branch-notes/feature-boundary-validation-mapping-contract]]
|
||
- 관련 raw topic: [[raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28]]
|
||
|
||
## Decision / 처리 결정
|
||
|
||
- 액션: `promote-to-canonical`
|
||
- 이유: `wiki/projects/ca-tmpl/boundary-validation-mapping.md` 에 Jackson default typing CVE static block 글감으로 반영했다.
|
||
- 다음 단계: source canonical이 `verified` 상태이므로 이후 `blogify` 대상으로 삼을 수 있다. 단 ArchUnit rule이 탐지 가능한 호출/참조 범위로 제한된다는 점을 유지한다.
|