- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다 - 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5 (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를 techviz 로 만들었다 - 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs 돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다. Concept 이 인용한 코드가 SSOT 에 없어 뺐다 - candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
123 lines
6.0 KiB
Markdown
123 lines
6.0 KiB
Markdown
---
|
|
kind: CASE
|
|
slug: analysis-finding-a16-f005
|
|
title: 설정으로 정한 파서 한계가 graphql-java에 설치되지 않는다
|
|
topic: graphql-surface
|
|
project: clean-architecture-backend-template
|
|
status: 게시 전
|
|
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
|
|
rootTreeNode: case:analysis-finding-a16-f005
|
|
evidenceCapturedOn: 2026-09-01
|
|
body: case-analysis-finding-a16-f005.body.md
|
|
assets:
|
|
- key: analysis-finding-a16-f005
|
|
file: ../../../final/evidence/rendered/analysis-finding-a16-f005.svg
|
|
evidence:
|
|
- ../../../final/evidence/raw/analysis-finding-a16-f005.txt
|
|
source:
|
|
- 원본 분석 절은 final/document.md#a16#L511 이다.
|
|
---
|
|
|
|
# 설정으로 정한 파서 한계가 graphql-java에 설치되지 않는다
|
|
|
|
파서 계층은 이 방어의 첫 번째 관문이다. 리프가 한계를 값으로 갖고 설치 함수도 갖는데 호출하는 코드가 없다. 파서 옵션이 정적 전역이라 시작 시 한 번 설치하지 않으면 라이브러리 기본값이 유지된다.
|
|
|
|
## 관계
|
|
|
|
- **배열 원소 상한이 선언만 되고 강제되지 않으며 백스톱도 없다**
|
|
같은 형태의 선언과 강제 어긋남이다.
|
|
- **5계층 예산 모델에서 요청 계층만 강제되고 나머지 파생이 전부 미배선이다**
|
|
같은 리프의 다른 미배선 사례다.
|
|
- **설정은 받아들여지고 검증되며 효과가 없다**
|
|
이 사례가 그 규칙의 형태다.
|
|
|
|
## 문제
|
|
|
|
파서 계층은 이 프로토콜의 서비스 거부 방어에서 첫 번째 관문이다.
|
|
|
|
복잡도 계산도 구조 분석도 문서를 파싱한 뒤에 일어나므로, 파싱 자체를 폭발시키는 문서는 그 앞에서 막아야 한다.
|
|
|
|
이 리프가 그 한계를 실제로 거는지 확인했다.
|
|
|
|
## 결론
|
|
|
|
걸지 않는다.
|
|
|
|
한계를 값으로 갖는 타입이 있고 클라이언트 정책에서 파생된다.
|
|
|
|
설치 함수도 있다. 연산 기본값 설치라는 이름이다.
|
|
|
|
호출하는 코드가 없다.
|
|
|
|
이름이 가리키듯 이 라이브러리의 파서 옵션은 정적 전역이다. 시작 시 한 번 설치하지 않으면 라이브러리 기본값이 유지된다.
|
|
|
|
실패 시나리오는 이렇다.
|
|
|
|
운영자가 설정으로 파서 한계를 조인다.
|
|
|
|
그 값은 플랫폼 설정을 거쳐 클라이언트 정책까지 도달한다. 그러나 한계 타입을 만드는 팩토리를 부르는 코드가 없어 파서에 닿지 않는다.
|
|
|
|
실제로 적용되는 것은 라이브러리의 기본값이다.
|
|
|
|
설정은 받아들여지고 검증되며 효과가 없다.
|
|
|
|
노출의 크기는 라이브러리 기본값이 정한다.
|
|
|
|
이 판본은 토큰 수와 공백 토큰 수와 규칙 깊이에 자체 기본 상한을 두므로 무제한은 아니다.
|
|
|
|
그리고 구조 한계와 복잡도 계산은 배선되어 있어 파싱 이후 계층은 작동한다.
|
|
|
|
그래서 P1 이 아니라 P2 다. 침묵하는 설정 표면이자 방어 계층 하나의 부재다.
|
|
|
|
권고는 플랫폼 자동 설정에 시작 시 한 번 설치를 부르는 초기화 지점을 두는 것이다.
|
|
|
|
정적 전역이므로 빈 메서드보다 초기화 콜백이 적절하다.
|
|
|
|
## 검증 환경
|
|
|
|
확인 방식 : 설치 함수 호출자 검색과 파서 옵션 전역성 확인
|
|
소스 수정 : x
|
|
|
|
## 재현 조건
|
|
|
|
원문은 final/evidence/raw/182 계열에 있다.
|
|
|
|
1. 파서 한계 타입과 설치 함수를 확인한다.
|
|
2. 설치 함수의 호출자를 센다.
|
|
3. 라이브러리의 파서 옵션이 정적 전역인지 확인한다.
|
|
4. 설정 값이 어디까지 도달하는지 추적한다.
|
|
5. 구조 한계와 복잡도 계산이 배선되는지 확인한다.
|
|
|
|
## 본문
|
|
|
|
<!-- body:start -->
|
|
|
|
파서 계층은 GraphQL DoS 방어의 **첫 번째** 관문이다 — 복잡도 계산도 구조 분석도 문서를 파싱한 뒤에 일어나므로, 파싱 자체를 폭발시키는 문서는 그 앞에서 막아야 한다.
|
|
|
|
## 파서 계층이 첫 관문인 이유
|
|
|
|
:::evidence key="analysis-finding-a16-f005" alt="분석 문서 final/document.md#a16 에서 이 기록의 근거 절을 그대로 잘라낸 15줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md#a16 발췌 — 15줄" zoom="true"
|
|
:::
|
|
|
|
## 값도 있고 설치 함수도 있고 호출하는 코드가 없다
|
|
|
|
이 leaf는 그 한계를 값으로 갖고(`GraphQlParserLimits`, 클라이언트 정책에서 파생), 설치 함수를 갖는다(`GraphQlParserOptionsFactory.installOperationDefaults`). `installOperationDefaults`라는 이름이 가리키듯 graphql-java의 파서 옵션은 정적 전역(`ParserOptions.setDefaultOperationParserOptions`)이고, 시작 시 한 번 설치하지 않으면 라이브러리 기본값이 유지된다.
|
|
|
|
## 실패 시나리오
|
|
|
|
운영자가 `backend.graphql.limits.*`로 파서 한계를 조인다. 그 값은 `GraphQlPlatformSettings` → `GraphQlClientPolicy`까지 도달하지만 `GraphQlParserLimits.from(...)`을 부르는 코드가 없어 파서에 닿지 않는다. 실제로 적용되는 것은 graphql-java 25.0의 기본값이다. 설정은 받아들여지고 검증되며 효과가 없다.
|
|
|
|
## 노출의 크기는 라이브러리 기본값이 정한다
|
|
|
|
graphql-java 25.0은 토큰 수·공백 토큰 수·규칙 깊이에 자체 기본 상한을 두므로 무제한은 아니다. 그리고 구조 한계(`GraphQlDocumentShapeAnalyzer`, autoconf=4)와 복잡도 계산(autoconf=4)은 배선돼 있어 파싱 이후 계층은 작동한다. 그래서 P1이 아니라 P2다 — 침묵하는 설정 표면이자 방어 계층 하나의 부재다.
|
|
|
|
## 권고
|
|
|
|
`GraphQlPlatformAutoConfiguration`에 시작 시 `GraphQlParserOptionsFactory.installOperationDefaults(GraphQlParserLimits.from(clientPolicy))`를 한 번 호출하는 초기화 지점을 둔다. 정적 전역이므로 `@Bean` 메서드보다 `InitializingBean`/`SmartInitializingSingleton`이 적절하다.
|
|
|
|
## 확인하지 못한 것
|
|
|
|
파서를 폭발시키는 문서를 보내 라이브러리 기본값이 적용되는지 재현하지 않았다. 호출자 부재상 그 결과가 나온다.
|
|
|
|
<!-- body:end -->
|