본문으로 건너뛰기

37. 웹 캐시 포이즈닝: CDN을 공격 표면으로 만들기

캐시 포이즈닝은 캐시가 틀린 응답을 저장하는 현상이 아니라, 캐시 키가 응답을 결정하는 모든 입력을 표현하지 못하는 현상이다. 호스트·언어·쿠키·헤더를 앱이 사용하면서 캐시는 URL만 키로 삼으면, 한 요청의 변형이 다른 요청의 응답으로 재사용될 수 있다. 검증은 승인된 랩이나 자기 소유 도메인에서 수행한다.

캐시 키와 응답의 계약

먼저 캐시 적중 여부를 식별할 헤더와 로그를 확보한다. Age, CDN의 cache-status 헤더, 응답 시간은 유용하지만 공급자마다 이름과 의미가 다르므로 단독 증거로 쓰지 않는다. 동일 URL에 허용된 Accept-Language, 인코딩, 인증 상태를 바꿔 요청하고, 캐시 키에 실제로 반영되는지 비교한다.

Vary는 필요한 요청 헤더를 알려주지만 만능 키 선언은 아니다. CDN이 Vary를 무시하거나 쿠키를 별도 정책으로 처리할 수 있으므로, 설정 문서와 실제 두 번째 요청의 응답을 함께 확인한다. 호스트 기반 절대 URL, 리다이렉트, 오류 페이지는 특히 캐시 저장 여부와 TTL을 확인할 가치가 있다. 테스트는 무해한 식별 문자열로 하고 외부 도메인으로의 리다이렉트나 사용자 데이터 노출을 만들지 않는다.

방어 설계

응답에 영향을 주는 입력은 명시적으로 캐시 키에 넣거나, 개인화 응답과 함께 캐시하지 않는다. 외부에서 전달된 X-Forwarded-Host 같은 헤더는 신뢰 프록시가 덮어쓴 값만 사용하고, 앱은 허용된 호스트 목록으로 URL을 만든다. Cache-Control: private와 짧은 TTL은 민감 응답의 기본값이며, 오류 응답 저장도 의도적으로 결정한다.

성공적인 검증은 “캐시를 오염시켰다”가 아니라, 어떤 입력이 키에서 빠졌고 그 결과가 누구에게 재사용될 수 있었는지를 설명한다. 배포 전 캐시 purge와 회귀 테스트까지 포함해야 수정이 운영 상태로 이어진다.