CORS 설정 오류: 와일드카드와 반사의 함정
Cross-Origin Resource Sharing (CORS)은 어떤 다른 웹사이트가 여러분의 API 응답을 읽을 수 있는지 제어합니다. 와일드카드나 반사된 origin 정책은 어떤 사이트든 인증된 요청을 보내고 결과를 읽게 할 수 있습니다.
무엇인가요
브라우저는 기본적으로 교차 출처 읽기를 차단합니다. CORS 헤더는 이를 선택적으로 완화합니다. Access-Control-Allow-Origin: *는 응답을 모든 웹사이트에 개방합니다.
더 미묘한 버그는 origin 반사입니다: 서버가 요청이 가져온 Origin을 그대로 allow-origin 헤더로 되돌려 보내, 구체적으로 보이면서 사실상 모두를 신뢰하는 것입니다.
왜 중요한가요
API가 사용자 데이터를 제공하고 자격 증명을 허용하면, 지나치게 넓은 CORS 정책은 악성 사이트가 로그인한 피해자의 데이터를 API에서 곧바로 읽게 합니다.
반사와 Access-Control-Allow-Credentials: true의 조합은 특히 위험합니다 — 보통 사용자 데이터를 비공개로 유지하는 동일 출처 보호를 무력화합니다.
고치는 방법
요청 Origin을 신뢰할 수 있는 도메인의 고정 목록과 대조하여 검증한 뒤에만 되돌려 보내세요.
const ALLOWED = new Set(["https://app.yourdomain.com"]);
const origin = req.headers.get("origin") ?? "";
const allow = ALLOWED.has(origin) ? origin : "";
// only set the header when allow is non-empty브라우저는 Access-Control-Allow-Origin: *와 자격 증명을 함께 쓰는 것을 금지하므로, 앱이 대신 origin을 반사하기도 하는데 — 그것이 바로 취약점입니다. 대신 엄격한 허용 목록을 사용하세요.
endpoint에 교차 출처 접근이 필요 없으면 CORS 헤더를 전혀 보내지 마세요. 정말 필요한 특정 route만 개방하세요.
자주 묻는 질문
Access-Control-Allow-Origin: *는 항상 나쁜가요?
진정으로 공개적이고 자격 증명이 없는 리소스(예: 공개 폰트나 공개 데이터 API)에는 아닙니다. 사용자 세션과 연결된 것에는 위험합니다.
CORS가 제 서버를 보호하나요?
아니요 — CORS는 서버가 아니라 브라우저가 적용합니다. 요청이 여러분에게 도달하는지가 아니라, 다른 사이트의 JavaScript가 무엇을 읽을 수 있는지를 관장합니다.