‘Hot‐Link & Bandwidth Abuse’ 문제를 막는 방법 - lets-go-trip/treaXure-backend GitHub Wiki

“만약 악의적인 사용자가 우리 서비스에 이미지를 올린 뒤, 해당 S3 URL을 외부 사이트에 퍼가서 마음대로 트래픽을 발생시키면 전송료가 폭증할 텐데, 이런 ‘핫링크 남용’ 문제를 어떻게 막아야 할까?”

1. 문제 정의

  • Hot‑Link(핫링크): 외부 사이트가 우리 CDN/S3 경로를 직접 <img src> 로 호출해 트래픽을 소비하는 행위
  • 위험
    • 전송료 폭증: CloudFront·S3 데이터 전송 요금 증가
    • 서비스 품질 저하: 캐시 히트율↓, 엣지 PoP 부하↑
    • 콘텐츠 도용: 저작권·브랜드 이미지 훼손

2. 위협 식별 & 징후

징후 지표 확인 방법
특정 IP·ASN 대량 요청 CloudFront Requests, WAF Rate metric CloudWatch / WAF 실시간
Referrer NULL·타 도메인 CloudFront Access‑Log cs(Referer) Athena 쿼리
회피형 User‑Agent (bot) ua 필드 탐색 Amazon Kinesis Firehose → S3 분석
전송요금 급등 Cost Explorer CloudFront-DataTransfer-Out-Bytes Cost Anomaly Detection 경보

3. 방어 레이어 별 비교

계층 기법 특징 장·단점 권장 상황
전송(Edge) Signed URL / Cookie 만료·IP범위 포함 서명 토큰 캐시 재활용률 관리 필요 로그인 사용자, 개인 콘텐츠
  WAF Rate‑Based Rule 분당 n회 이상 블록 공유IP 환경 오탐 가능 DDoS·스크래핑 완화
오리진(S3) Origin Access Control(OAC) S3를 Private 유지 설정 단순, 공개 차단 모든 환경(기본)
애플리케이션 Download Token DB 저장 세밀한 권한·통계 서버 라운드트립 필요 비공개 다운로드, 영수증 등
비용통제 Budgets & Auto‑WAF Action 한도 초과 시 자동 차단 초기 설정 필요 소규모 팀 비용 폭주 방지

4. 주요 솔루션 세부 가이드

4‑1. CloudFront Signed URL / Cookie

  1. 키쌍 생성: RSA 2048 → CloudFront Key Group 업로드

  2. 백엔드(Spring)에서 CloudFrontUrlSigner로 URL 서명

    • 정책 예: ResourcePath:/user/*, Expires:+120s, IP:203.0.113.0/24
  3. 쿠키 방식: CloudFront-Signature, Key-Pair-Id, Policy 3종 세트 → 브라우저 Set‑Cookie

    쿠키 이름 역할 주요 내용
    CloudFront-Key-Pair-Id 어떤 공개 키로 검증할지 지정 • Key group 또는 Trusted key group 에 등록된 공개 키 ID. • CloudFront는 이 ID로 대응하는 공개 키를 찾아 서명을 검증합니다.
    CloudFront-Policy(또는 CloudFront-Expires) 요청 허용 조건을 담은 정책(Policy) 자체 • Base64-URL 인코딩된 JSON 문서. • 포함 정보 — Resource(허용 경로 패턴), DateLessThan(만료 시각, Unix epoch), IpAddress(선택) 등. • Custom Policy를 쓰면 CloudFront-Policy가, Canned Policy를 쓰면 대신 CloudFront-Expires(만료 타임스탬프)만 전달됩니다.
    CloudFront-Signature 정책 무결성 서명 • 위 Policy(또는 “경로+만료” 문자열)를 RSA-SHA1로 서명한 값.• 사이트 간 복사·변조를 막고, CloudFront가 정책이 진짜임을 입증합니다.

    요약 흐름

    1. 백엔드정책 → SHA1 해시 → RSA 개인키로 서명 → 세 쿠키를 Set-Cookie 헤더로 반환.
    2. 브라우저가 CloudFront 도메인에 요청 → 세 쿠키 자동 전송.
    3. CloudFrontKey-Pair-Id에 해당하는 공개 키로 Signature를 검증하고, Policy 조건(경로, IP, 만료)을 모두 만족하면 오리진(S3 등)에 요청을 프록시합니다.
  4. 캐시 고려:

    • Signed URL: 객체별 서명값 달라 캐시 적중률↓
    • Signed Cookie: 동일 객체 동일 쿠키로 캐시 히트율↑
  5. TTL 전략: Public 이미지(썸네일) 10‑30 min, Private 파일 1‑5 min

4‑2. AWS WAF Hot‑Link 룰

IF  request.header['referer'] NOT contains "app.example.com"
THEN block (403)
  • Rate‑Based Rule: 2분당 2000 requests/IP 초과 시 1시간 차단
  • Header Tamper 방지: 추가로 User‑Agent 길이·정규식 필터

4‑3. 비용 알람 & 자동 대응

  1. AWS Budgets – ‘DataTransfer‑CF’ 5 USD 초과 시 SNS 주제 발행
  2. Lambda Budget Action → WAF Rule Priority 0 ‘Block‑All’ enable
  3. 복구 절차: 원인 분석 후 Rule disable → 캐시 무효화

5. 구현 체크리스트

  • S3 버킷 Public Access Block 유지 & OAC 연결
  • CloudFront 배포 Behaviour /images/* → Cache Policy: Signed‑Cookie
  • RSA Private Key 안전보관 (Parameter Store SecureString)
  • 백엔드 /images/token API 구현 – 403 on quota exceed
  • WAF WebACL 연동 & 테스트 (Referrer + Rate)
  • Cost Anomaly Detection 활성화, cloudfront DIMENSION 추적
  • 월간 트래픽 리포트 Athena→QuickSight 대시보드

6. 참고 리소스

  • AWS Docs » Serving private content with CloudFront signed URLs and signed cookies
  • AWS Samples » cloudfront‑signed‑url‑spring‑boot (GitHub)
  • AWS WAF Developer Guide » Managing rate‑based rules

요약 — Signed URL/Cookie로 1차 인증, WAF와 Budgets로 2차 한도 방어를 구축하면, 공유 URL이 퍼져도 몇 분 내 무효화되고, 전송료 폭주 시 자동 차단까지 가능하다.

⚠️ **GitHub.com Fallback** ⚠️