Skip to content

feat(security): P1 보안 강화 — WebSocket CORS, 파일 업로드 검증, Rate Limiting - #333

Draft
alpin87 wants to merge 4 commits into
mainfrom
feat/p1-security-hardening
Draft

feat(security): P1 보안 강화 — WebSocket CORS, 파일 업로드 검증, Rate Limiting#333
alpin87 wants to merge 4 commits into
mainfrom
feat/p1-security-hardening

Conversation

@alpin87

@alpin87 alpin87 commented May 30, 2026

Copy link
Copy Markdown
Contributor

개요

KISA AI 보안 가이드라인 / OWASP Top 10 기준 Priority 1 보안 취약점 중 3건을 조치합니다. (AI 텍스트 필터링 P1-2/P1-5는 별도 AI 서비스 영역이라 제외)

  • P1-4 WebSocket CORS 제한
  • P1-1 파일 업로드 보안 (CRITICAL)
  • P1-3 Rate Limiting

변경 내용

🔒 P1-4 — WebSocket CORS (fix(security))

  • STOMP 엔드포인트(/ws/chat, /ws/blinddate)의 setAllowedOriginPatterns("*")authentication.origins 화이트리스트 재사용
  • CSWSH(교차 출처 WebSocket 하이재킹) 방지, REST/WebSocket CORS 정책 일원화

🔥 P1-1 — 파일 업로드 보안 (feat(security))

  • 매직바이트 기반 실제 이미지 타입 판별(JPEG/PNG/GIF/WEBP) — 클라이언트 확장자/Content-Type 불신
    • FileValidator, ImageSignatureDetector, ImageContentType
  • 저장 파일명·Content-Type을 판별 결과로 결정 → 확장자 위장(.png로 위장한 HTML/SVG)·stored XSS 차단
  • 빈 파일/크기 상한(10MB) 검증, getOriginalFilename() NPE 및 dead code 제거
  • multipart 한도 max-file-size: 10MB / max-request-size: 35MB (기본 1MB가 검증을 무력화하던 문제 해결)
  • MaxUploadSizeExceededException413 매핑

🚦 P1-3 — Rate Limiting (feat(security))

  • IP 기준 제한: 로그인/소셜 5회/분, 이메일 발송 5회/분, 검색 30회/분
  • Redis Lua 스크립트로 INCR+PEXPIRE 원자 처리(고정 시간창) → TTL 유실 영구 키 방지
  • RateLimitFilterJwtFilter 앞에 등록 + FilterRegistrationBean.setEnabled(false)로 서블릿 자동 등록 차단(이중 카운트 방지)
  • List<RateLimitRule> 주입 함정을 RateLimitRules 홀더로 회피
  • raw XFF 파싱 제거 → prod forward-headers-strategy: framework 위임(IP 스푸핑 방지), Redis 장애 시 fail-open

검증

  • ./gradlew compileJava 통과
  • ✅ 독립 코드 리뷰 1회 + 지적된 HIGH 5건(멀티파트 1MB 무력화, XFF 스푸핑, INCR/EXPIRE 비원자, WEBP 청크 미검증, 필터 이중등록) 반영

⚠️ 머지 전 확인 필요

  • WebSocket 네이티브(앱) 클라이언트 Origin"*" → 화이트리스트로 좁혔습니다. Origin 헤더를 보내지 않는 네이티브 클라는 통과되어 보통 안전하나, 앱이 WebSocket에 Origin을 실어 보낼 경우 핸드셰이크가 막힐 수 있어 /ws/chat·/ws/blinddate 실제 앱 스테이징 연결 테스트 필요
  • 운영 LB가 인바운드 X-Forwarded-For를 덮어쓰는지(스푸핑 방지 전제) 확인
  • (선택) 단위 테스트 추가: ImageSignatureDetector, FileValidator, RateLimitFilter

🤖 Generated with Claude Code

alpin87 and others added 3 commits May 30, 2026 22:30
STOMP 엔드포인트(/ws/chat, /ws/blinddate)의 setAllowedOriginPatterns("*")를 SecurityConfig가 사용하는 authentication.origins 화이트리스트로 교체하여 CSWSH(교차 출처 WebSocket 하이재킹)를 방지하고 REST/WebSocket CORS 정책을 일원화한다.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ts (P1-1)

- 매직바이트(파일 시그니처)로 실제 이미지 타입(JPEG/PNG/GIF/WEBP)을 판별하는 FileValidator/ImageSignatureDetector 추가. 클라이언트 확장자/Content-Type을 신뢰하지 않는다.
- 저장 파일명과 Content-Type을 판별 결과로 결정하여 확장자 위장(.png로 위장한 HTML/SVG) 및 stored XSS 차단.
- 빈 파일/크기 상한(10MB) 검증, getOriginalFilename() NPE 및 dead code 제거.
- multipart 한도를 max-file-size 10MB / max-request-size 35MB로 설정(기본 1MB가 검증을 무력화하던 문제 해결).
- MaxUploadSizeExceededException을 413으로 매핑하는 핸들러 추가.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(P1-3)

- 남용 위험이 높은 엔드포인트(로그인/소셜 5회·분, 이메일 발송 5회·분, 검색 30회·분)에 IP 기준 Rate Limiting 적용.
- Redis Lua 스크립트로 INCR+PEXPIRE를 원자적으로 처리(고정 시간창). TTL 유실로 인한 영구 키 문제 방지.
- RateLimitFilter를 JwtFilter 앞에 등록하고, FilterRegistrationBean.setEnabled(false)로 서블릿 컨테이너 자동 등록을 막아 이중 카운트 방지.
- List<RateLimitRule> 주입 함정을 RateLimitRules 홀더로 회피.
- raw X-Forwarded-For 파싱 대신 server.forward-headers-strategy=framework로 위임하여 IP 스푸핑 방지(prod). Redis 장애 시 가용성 우선 fail-open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 36ba78a6-6aca-4422-9f23-f5a072243f4b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/p1-security-hardening

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

SecurityConfig가 RateLimitFilter를 의존하게 되면서, Filter 타입 빈을 자동 포함하는 @WebMvcTest 슬라이스가 RateLimitFilter의 StringRedisTemplate 의존성을 해소하지 못해 컨텍스트 로딩에 실패했다. 기존 JwtFilter 목 처리와 동일하게 15개 슬라이스 테스트에 RateLimitFilter @MockitoBean을 추가한다.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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