이정수
|
08d191ff2e
|
feat(upload): W3-5 Unity WebGL 업로드 보안 보강 — zip-slip/심링크/zip bomb/포맷검증/권한게이트/자산 생명주기/감사
- ZipSecurity 추출 코어: validateEntryName 사전거부(절대/UNC/백슬래시/NUL/`..`/길이>255/깊이>32) + normalize startsWith 경계 + assertParentNotSymlink(부모 walk) + 쓰기후 toRealPath 재검증(zip-slip 심층방어). 기존 골격 보강(재작성 아님)
- zip bomb 3중 상한(엔트리당 256MB/누적 512MB/엔트리수 8000), 실제 읽은 바이트 누적(getCompressedSize 미사용). 포맷: 매직바이트 PK + MIME·확장자 AND + Unity 산출물(loader/framework/data/wasm + index.html, .br/.gz 변형 허용)
- 권한 게이트 통일: 진입부 PermissionGate.isAuthenticated(임시 role 직접체크 0, 신규 게이트 메서드 0) + mode=jam 시 GAME_JAM_MANAGE 옵션. 일반 업로드 개방 유지
- 원자적 교체: 임시추출(.tmp/{uuid})→검증→ATOMIC_MOVE swap(미지원 REPLACE 폴백 + finally 복원). replaceUuid 소유검증(UUID 정규화→LIKE 와일드카드 주입 차단, 불일치/비소유 403)
- 자산 생명주기: GameAssetCleanupService.purgeByWebglPath(경계검증) + GameController updateGame/deleteGame 훅(고아 정리)
- 감사: game_upload_audit_log(outcome CHECK·reject_reason 11코드 enum↔DDL 정합) docs/game-upload-ddl.sql 권위 + schema.sql 동기. GameUploadAuditMapper #{} only
- /game/** 서빙 현행 유지(GameAssetController 불변, 신설 안 함 — 조사 stale 정정)
검증: 컨테이너 ./mvnw -o test 318/318 GREEN(신규 31: ZipSecurityTest 20·GameUploadControllerSecurityTest 11), 회귀 0. L2 격리 throwaway DB contract PASS(insertAudit 8컬럼·outcome CHECK·FK·findGameByWebglUuid alias). adversarial zip-slip 감사 SOUND(심링크 TOCTOU 구조적 불가·경로탈출/유니코드/zipbomb/LIKE주입 전수 차단). 실 dev DB 무접촉.
알려진 잔여(배포 하드닝, LOW): 업로드 저장루트(static/game)가 WAR 정적 서빙트리 내 → 기본 classpath:/static/** 핸들러로 transient .tmp 노출 가능성. 저장루트를 서빙트리 밖으로 이전 권고(gameRoot 경로중첩 정합과 함께). transient+검증콘텐츠라 영향 제한.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3FeMrbtxfTScjrwUukyHD
|
2026-06-29 12:10:55 +09:00 |