--- kind: CASE slug: analysis-finding-a14-f004 title: 프레임워크 자유 신원 모델과 교차 테넌트 가드가 프로덕션에서 한 번도 참조되지 않는다 topic: web-inbound-and-http-surface project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: case:analysis-finding-a14-f004 evidenceCapturedOn: 2026-09-01 body: case-analysis-finding-a14-f004.body.md assets: - key: analysis-finding-a14-f004 file: ../../../final/evidence/rendered/analysis-finding-a14-f004.svg evidence: - ../../../final/evidence/raw/analysis-finding-a14-f004.txt source: - 원본 분석 절은 final/document.md#a14#L562 이다. --- # 프레임워크 자유 신원 모델과 교차 테넌트 가드가 프로덕션에서 한 번도 참조되지 않는다 보안 패키지 열한 파일이 서로만 참조하고 바깥에서 들어오는 화살표가 없다. 그 안에 클라이언트가 소속을 제안하는 헤더를 거부하는 가드가 있는데, 도달 경로의 호출자가 테스트뿐이다. 지금 이 플랫폼은 그 헤더를 거부도 무시도 하지 않는다. ## 관계 - **플랫폼 요청 컨텍스트가 서블릿에는 생산자가 없고 리액티브에는 익명 액터로 고정되어 있다** 이 가드를 고칠 때 함께 연결해야 하는 사례다. - **용량 보호 계층 전체가 자기 테스트 픽스처 안에서만 실행된다** 같은 리프의 같은 형태다. - **노출이 없는 것과 가드가 작동하는 것은 다르다** 이 사례가 그 규칙의 형태다. ## 문제 이 리프에 프레임워크에 의존하지 않는 신원 모델이 있다. 그 패키지가 바깥에서 쓰이는지 확인했다. ## 결론 쓰이지 않는다. 보안 패키지 열한 파일이 서로만 참조하고 바깥에서 들어오는 화살표가 없다. 인증 조회 값을 만드는 production 코드가 없으므로 보안 문맥 다리의 해석 메서드가 호출될 수 있는 상태 자체가 없다. 가장 값이 큰 부분이 그 안에 있다. 소속 문맥 해석기가 클라이언트가 소속을 제안하는 헤더 이름 넷을 알고 있고, 그 이름이 요청 입력에 있으면 거부 예외를 던진다. 도달 경로는 보안 문맥 다리의 두 인자 오버로드 하나뿐이고, 그 오버로드의 호출자는 테스트뿐이다. 그래서 지금 이 플랫폼은 그 헤더에 대해 거부도 무시도 하지 않는다. 그 헤더를 보는 코드가 아예 없다. 노출은 아니다. 소속을 소비하는 유일한 지점이 요청 컨텍스트의 소속을 읽는데, 그 값은 다른 사례 때문에 항상 비어 있다. 헤더가 소속이 되는 경로가 없으므로 교차 소속 읽기도 없다. 그러나 그것은 가드가 작동해서가 아니라 소속 기능 전체가 배선되지 않아서다. 요청 컨텍스트를 고치면서 이 가드를 함께 연결하지 않으면, 그때 노출이 생긴다. 이 패키지에는 교차 출처 정책 검증기와 위조 방지 정책 해석기도 있고 둘 다 production 참조가 0 이다. 실제 두 결정은 보안 설정이 프레임워크 API 로 직접 내린다. 같은 질문에 대한 두 번째 구현이 검증만 되고 쓰이지 않는다. 판정은 P2 다. ## 검증 환경 Spring Boot : 4.0.8 확인 방식 : 패키지 간 참조 방향 확인과 호출자 전수 검색 소스 수정 : x ## 재현 조건 원문은 final/evidence/raw/176 계열에 있다. 1. 보안 패키지의 파일 목록을 만든다. 2. 각 타입을 참조하는 바깥 코드를 검색한다. 3. 소속 해석기의 거부 메서드 도달 경로를 확인한다. 4. 그 경로의 호출자를 센다. 5. 소속을 소비하는 지점이 읽는 값이 무엇인지 확인한다. 6. 교차 출처와 위조 방지 결정이 실제로 어디서 내려지는지 확인한다. ## 본문 `security` 패키지 11개 파일이 서로만 참조하고 바깥에서 들어오는 화살표가 없다(§11.1). ## AuthenticationView 참조 위치 :::evidence key="analysis-finding-a14-f004" alt="코드베이스에서 AuthenticationView 를 검색한 출력 5줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="AuthenticationView 코드베이스 검색 — 5줄 · exit 0" zoom="true" ::: ## 호출될 수 있는 상태 자체가 없다 `AuthenticationView`를 만드는 프로덕션 코드가 없으므로 `WebSecurityContextBridge.resolve(...)`가 호출될 수 있는 상태 자체가 없다. ## 가장 값이 큰 부분이 그 안에 있다 ```java // WebTenantContextResolver.java private static final Set TENANT_INPUT_NAMES = Set.of("x-tenant-id", "tenant-id", "tenantid", "tenant"); public void rejectTenantInput(Map requestInput) { ... throw new UntrustedTenantInputException(); } ``` 클라이언트가 테넌트를 제안하는 헤더를 거부하는 가드다. 도달 경로는 `WebSecurityContextBridge.resolve(authentication, requestInput)` 오버로드 하나뿐이고, 그 오버로드의 호출자는 테스트뿐이다. 그래서 지금 이 플랫폼은 `X-Tenant-Id` 헤더에 대해 **거부도 무시도 하지 않는다** — 그 헤더를 보는 코드가 아예 없다. ## 노출은 아니지만 가드가 작동해서가 아니다 테넌트를 소비하는 유일한 지점(`OperationAccessPolicy:37-40`)이 `context.tenant()`를 읽고, 그 값은 §12.1 때문에 항상 비어 있다. 헤더가 테넌트가 되는 경로가 없으므로 교차 테넌트 읽기도 없다. 그러나 그것은 **테넌트 기능 전체가 배선되지 않아서**다. §12.1을 고치면서 이 가드를 함께 연결하지 않으면 그때 노출이 생긴다. ## 같은 질문에 대한 두 번째 구현 이 패키지에는 `WebCorsPolicyValidator`(96줄)와 `WebCsrfPolicyResolver`(43줄)도 있고 둘 다 프로덕션 참조 0이다. 실제 CORS·CSRF 결정은 `SecurityConfig`가 Spring Security API로 직접 내린다. P2. ## 확인하지 못한 것 소속 제안 헤더를 붙여 요청을 보내 아무 일도 일어나지 않는 것을 재현하지 않았다. 참조 부재상 그 결과가 나온다.