🌍 CORS 테스터
선택한 Origin에서 CORS 프리플라이트(OPTIONS)와 실제 요청을 보내 Access-Control-Allow-Origin / Methods / Headers / Credentials / Max-Age를 진단.
📚 CORS 기초
• 브라우저는 다른 origin에 대한 fetch / XHR를 차단합니다.
• CORS는 서버가 Access-Control-Allow-Origin으로 허용된 origin을 선언합니다.
• 프리플라이트는 브라우저가 실제 요청 전에 보내는 OPTIONS 요청입니다. 커스텀 헤더나 단순하지 않은 메서드 (PUT, DELETE 등)를 사용할 때 발생합니다.
• Access-Control-Allow-Credentials: true 와 Access-Control-Allow-Origin: * 결합할 수 없음 — 특정 origin을 사용해야 함.
📖 이 진단으로 알 수 있는 것
이 진단은 Origin 헤더를 붙인 요청과 프리플라이트 OPTIONS 를 실제로 보내 돌아오는 Access-Control-* 헤더를 확인합니다. 전제로서 CORS 를 강제하는 것은 브라우저뿐입니다. curl 이나 서버 간 통신은 CORS 를 전혀 보지 않습니다. 즉 CORS 는 API 를 지키는 구조가 아니라 이용자의 브라우저에 저장된 자격 증명이 악의적인 사이트에서 멋대로 쓰이는 것을 막는 구조입니다.
| 판정 항목 | 무엇을 보는가 | 걸렸을 때의 대처 |
|---|---|---|
| 여러 오리진을 나열함 | Access-Control-Allow-Origin 에 쓸 수 있는 것은 오리진 하나 또는 * 뿐입니다. 쉼표로 여러 개를 나열한 헤더는 사양상 부정이며 브라우저는 통째로 거부합니다. 설정했는데도 CORS 오류가 난다는 원인으로 매우 많은 표기입니다. |
서버 측에서 요청의 Origin 을 화이트리스트와 대조해 일치한 그 하나만 그대로 돌려줍니다. 이때 응답은 Origin 마다 내용이 달라지므로 Vary: Origin 을 반드시 붙이세요. 빠뜨리면 CDN 이 첫 건을 캐시해 다른 오리진용 응답을 배포해 버립니다. |
| 프리플라이트가 매번 발생 | Content-Type: application/json 을 보내거나 Authorization · 독자 헤더를 붙이거나 GET / POST / HEAD 이외의 메서드를 쓰면 단순 요청이 아니게 되어 본 요청 앞에 OPTIONS 왕복이 한 번 늘어납니다. API 를 호출할 때마다 왕복이 배가 되므로 지연이 큰 회선에서는 체감으로 직결됩니다. |
Access-Control-Allow-Headers 에 실제로 보내는 헤더를 빠짐없이 나열하고(여기에 없는 헤더가 하나라도 있으면 프리플라이트가 실패합니다) Access-Control-Max-Age 로 프리플라이트 결과를 캐시시킵니다. 크롬의 상한은 7200초이므로 그 이상을 지정해도 잘립니다. |
| 오류 응답에 CORS 헤더가 없음 | 많은 프레임워크는 예외가 발생해 500 을 돌려줄 때 미들웨어를 거치지 않아 Access-Control-Allow-Origin 이 붙지 않은 채 응답합니다. 그러면 브라우저가 내용을 읽게 해 주지 않으므로 콘솔에는 CORS 오류라고만 나옵니다. 진짜 원인인 서버 측 예외가 완전히 가려지는 매우 성가신 상태입니다. |
예외 핸들러나 error_page 의 응답에도 같은 CORS 헤더를 붙이세요. 원인 분리 절차로는 개발자 도구 Network 탭에서 실제 상태 코드를 보는 것이 먼저입니다. 여기가 500 이나 404 라면 CORS 설정은 무관하며 고쳐야 할 것은 앱 쪽입니다. |
CORS 는 인가가 아닙니다. Access-Control-Allow-Origin: * 을 붙이든 안 붙이든 API 자체는 누구나 curl 로 호출할 수 있습니다. 지켜야 할 데이터가 있다면 토큰 인증이나 세션 검증을 구현하세요. 또 하나의 오해는 CORS 를 설정하면 CSRF 도 막을 수 있다는 것으로 이는 성립하지 않습니다. <form> 전송이나 <img> 로드는 애초에 CORS 관할 밖이기 때문입니다. CSRF 에는 SameSite 쿠키와 CSRF 토큰이 별도로 필요합니다.