Skip to content

PII 마스킹이 자동 적용된다는 서술 정정 - #220

Merged
i3months merged 1 commit into
devfrom
docs/pii-masker-reality
Aug 24, 2026
Merged

PII 마스킹이 자동 적용된다는 서술 정정#220
i3months merged 1 commit into
devfrom
docs/pii-masker-reality

Conversation

@i3months

Copy link
Copy Markdown
Member

문제

로깅 축을 감사하다 나온 건이다. 문서 세 곳이 마스킹을 이미 걸려 있는 통제처럼 서술한다.

문서 서술
observability.md §9 "운영 로그에 자동 마스킹할 패턴" + PiiMasker 지목
security.md §7 "마스킹 대상은 LoggingMasker 유틸로 일괄 처리"
backend/CLAUDE.md §14 "민감정보 마스킹: PiiMasker.java"

실제로는:

  • PiiMasker 를 부르는 곳이 하나도 없다 (자기 자신 외 참조 0건)
  • 로그 파이프라인에 필터로 꽂혀 있지도 않다
  • LoggingMasker 는 아예 존재하지 않는 이름이다

이게 왜 문제냐면, security.md §7 은 "절대 로그에 남기지 않는다" 목록(이력서 본문·답변 본문 등) 바로 아래에서 "일괄 처리된다"고 말한다. 읽는 사람은 "운영은 마스킹되니 남겨도 되겠네" 로 이해한다 — 문서가 막으려던 실수를 문서가 유도하는 상태다.

그럼 걸면 되지 않나 — 안 된다

PiiMasker.mask() 를 Logback 컨버터로 전 로그에 적용하면 분산 추적이 깨진다. 전화번호 패턴 (?<!\d)(?:\+?\d[\d .-]{7,}\d)(?!\d) 이 구분자 포함 9자리 이상 숫자열을 전부 잡기 때문이다. 실제로 돌려본 결과:

traceId=01234567-89ab-cdef-0123-456789abcdef
  → traceId=***-***-6789ab-cdef-***-***-6789abcdef

session ended at 1755993600000
  → session ended at ***-***-0000

X-Trace-Id 상관관계는 Core·AI·RealTime 을 잇는 유일한 수단이다(루트 CLAUDE.md §4). 이걸 잃는 대가가 "혹시 모를 PII"보다 크다.

그리고 실익도 없다 — 이번에 백엔드·AI 로그를 훑은 결과 모두 식별자만 남기고 본문을 남기지 않는다:

  • 백엔드: sessionId=, messageId=, userId=, key= 형태. 답변·이력서 본문을 찍는 곳 없음
  • AI: structlog 호출에 text=/content=/prompt=/chunk_text 류 필드 없음
  • ai_request_logs 스키마: 토큰 수·지연시간·상태만. 프롬프트·응답 본문 컬럼 자체가 없음

1차 방어(애초에 안 남긴다)가 실제로 지켜지고 있고, 마스킹은 그 위의 보조 수단인데 지금 형태로는 부작용이 더 크다.

수정

문서를 현실에 맞췄다 — 자동 아님, 호출부 전용, 그리고 왜 안 거는지를 근거와 함께.

PiiMasker 클래스 Javadoc 에도 같은 경고를 달았다. 다음 사람은 문서가 아니라 클래스에서 시작할 가능성이 높고, "호출부가 없네, 빠뜨렸구나" 하고 전역으로 꽂는 게 자연스러운 반응이라서다. "없어서 빠뜨린 게 아니라 안 거는 쪽을 택한 것"이라고 명시했다.

테스트

PiiMaskerTest 6건 — 이 클래스에 테스트가 하나도 없었다.

  • 개별 마스킹 4건 (이메일·전화·GitHub 토큰·자유 텍스트 내 탐지)
  • 위험 고정 2건: 전역 적용 시 트레이스 ID·epoch millis 가 손상된다

후자를 테스트로 남긴 이유는, 문서에 적는 것만으로는 컨버터로 꽂는 걸 막지 못하기 때문이다. 이 두 테스트가 실패한다면 전화번호 패턴이 개선된 것이므로, 그때 문서·Javadoc 의 근거도 함께 갱신하면 된다.

이번 감사에서 별도로 확인한 것

ai_request_logs.error_message 에는 AI 가 str(error)[:1000] 을 넣는다(#194 와 같은 계열). 다만 브라우저로 나가는 SSE 와 달리 내부 DB 테이블이고, LLM 콜백 단계 예외라 주로 게이트웨이 오류 본문·연결 오류다. 사용자 본문이 들어올 경로는 확인되지 않아 이번 범위에 넣지 않았다.

문서 세 곳이 마스킹을 이미 걸려 있는 통제처럼 서술했다.

- observability.md §9: "운영 로그에 자동 마스킹할 패턴" + PiiMasker 지목
- security.md §7: "마스킹 대상은 LoggingMasker 유틸로 일괄 처리"
  — LoggingMasker 는 존재하지 않는 이름이다
- backend/CLAUDE.md §14: "민감정보 마스킹: PiiMasker.java"

실제로는 PiiMasker 를 부르는 곳이 하나도 없다. 로그 파이프라인에 필터로
꽂혀 있지도 않다. 이 서술을 믿으면 "남겨도 알아서 가려진다"고 판단하게 되는데,
그건 이 문서가 막으려던 실수 그 자체다.

그렇다고 전역 필터로 꽂는 건 답이 아니다. 전화번호 패턴이 구분자 포함 9자리
이상 숫자열을 전부 잡아서 트레이스 ID 와 epoch millis 가 뭉개진다:

  traceId=01234567-89ab-cdef-0123-456789abcdef
    → traceId=***-***-6789ab-cdef-***-***-6789abcdef

X-Trace-Id 상관관계는 Core·AI·RealTime 을 잇는 유일한 수단이라 이걸 잃는
대가가 더 크다. 지금 백엔드·AI 로그는 모두 식별자만 남기고 본문을 남기지
않는 것으로 확인해서 전역 필터의 실익도 없다.

그래서 문서를 현실에 맞추고(자동 아님, 호출부 전용), 왜 안 거는지를 근거와
함께 남겼다. PiiMasker 클래스 Javadoc 에도 같은 경고를 달았다 — 다음 사람은
문서가 아니라 클래스에서 시작할 가능성이 높다.

테스트로도 고정했다. 개별 마스킹 동작 4건 + "전역 적용 시 트레이스 ID·epoch
millis 가 손상된다" 2건. 후자가 실패하면 패턴이 개선된 것이므로 그때 문서
근거도 함께 갱신하면 된다.
@i3months
i3months merged commit 4b6b1de into dev Aug 24, 2026
5 checks passed
@i3months
i3months deleted the docs/pii-masker-reality branch August 24, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant