콘텐츠로 이동

트러블슈팅 — 파일 없이 격자를 점령할 수 있었던 이유 (MSG-132)

요약

saveVideo가 s3Key를 검증 없이 저장해서 파일 업로드 없이 좌표만으로 지도 전체를 칠할 수 있었다 — 점령이 인코딩보다 먼저라 인코딩 실패도 못 막음. 수정: 검증 3종(소유권 prefix + 중복 existsBy+DB UNIQUE + 실존 headObject)을 saveVideo 진입부에 배치. prefix만으론 못 막는다(공격자가 자기 userId를 앎). UNIQUE는 새 V2 마이그레이션으로(V1 수정은 CI가 차단 — 32시간 다운 사고 재발 방지). 테스트 121건 통과. 미해결: 진짜 고아 객체(MSG-133)·기존 데이터 소급 검증.

이 노트로 답할 수 있는 질문

  • 파일 없이 격자를 점령할 수 있었던 원인은?
  • 인코딩이 실패해도 점령이 남는 이유는?
  • prefix 검사만으로는 왜 못 막나?
  • 최종 검증 3종은 각각 뭘 막나?
  • 왜 UNIQUE 제약을 V1이 아닌 V2 파일로 넣었나?
  • 앱 검사와 DB 제약을 둘 다 두는 이유는?
  • 아직 안 풀린 문제는?

요약

  • 원인: saveVideo가 s3Key 무검증 저장 + 점령(upsertUserGrid)이 인코딩 트리거보다 먼저 → 가짜 키로 200 OK·점령.
  • 발견: presigned URL 고아 객체 조사 중 부수 발견. 재현 테스트 5건 중 4건 실패로 확인 후 수정.

발견

  • prefix 검사(소유권)와 headObject(실존)는 서로 다른 걸 막는다 — 둘 다 필요.
  • 함정 2개: 기존 통합 테스트가 실제 AWS S3 호출(→ @MockitoBean S3Client), "같은 키 재업로드" 테스트가 현실과 다름(테스트가 낡음).
  • 앱 검사(existsBy)는 4xx UX용, DB UNIQUE는 동시성 최종 방어선.

시사점

  • 적용된 Flyway V 파일은 절대 수정 금지(CI 가드, MSG-130) — 스키마 변경은 항상 새 V 파일.
  • 미해결: "올렸는데 확정 안 한" 진짜 고아는 MSG-133에서(같은 prefix라 단순 만료 규칙 불가), 기존 저장 데이터 소급 검증은 운영 전 점검.

원본 링크

리포 문서: docs/explainers/MSG-132-troubleshooting.html · 관련 티켓: MSG-132·MSG-133·MSG-130