조회수: 21

Access-Control-Allow-Origin 헤더 없음 (CORS)

Access-Control-Allow-Origin 헤더가 없나요? 프리플라이트 실패, 정확한 오리진 반환, 자격증명 모드 3가지를 점검합니다. 무료 즉시 진단으로 바로 확인.

내 도메인에 이 문제가 있는지 지금 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.

Problem

브라우저 콘솔에 다음이 표시됩니다: Access to fetch at '...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Symptoms

  • curl이나 Postman에서는 되는데 브라우저에서만 실패합니다.
  • 서버 로그에는 200인데 페이지는 오류를 내고 데이터를 받지 못합니다.
  • 실패하는 호출 바로 앞에 정체불명의 OPTIONS 요청이 Network 탭에 나타납니다.

이 오류가 실제로 뜻하는 것

CORS는 서버가 아니라 브라우저가 강제합니다. WHATWG Fetch 표준에 정의돼 있고, 서버가 켜는 보안 기능이 아니라 동일 출처 정책(same-origin policy)의 완화입니다. 그래서 모두가 걸려 넘어지는 지점이 여기입니다: 응답은 거의 항상 도착합니다. 서버는 요청을 처리하고 200을 반환했으며 본문까지 보냈습니다. 브라우저는 그걸 전부 받았고 — 그런 다음, 페이지의 오리진을 가리키는 Access-Control-Allow-Origin 헤더가 없는 것을 보고 자바스크립트가 읽지 못하게 막았습니다.

curl은 되고 페이지는 안 되는 이유가 이것입니다. curl에는 강제할 동일 출처 정책이 없습니다. 해결은 절대 클라이언트 쪽이 아니라, 언제나 서버가 추가해야 할 응답 헤더입니다.

Top 3 Causes

  1. 서버가 헤더를 아예 안 보냄(또는 틀린 오리진을 보냄) - 가장 흔합니다. 응답에 Access-Control-Allow-Origin이 전혀 없거나, 호출한 페이지와 다른 오리진을 가리킵니다. 값은 *이거나 요청 오리진과 정확히 일치해야 합니다.
  2. 프리플라이트 OPTIONS 요청 실패 - “단순(simple)” 요청을 벗어나면 프리플라이트가 발생합니다. 단순이란 GET/HEAD/POST에 안전목록 헤더만 쓰고 Content-Typeapplication/x-www-form-urlencoded·multipart/form-data·text/plain인 경우입니다. JSON 본문, PUT/DELETE/PATCH, Authorization 같은 헤더를 보내는 순간 브라우저는 먼저 Access-Control-Request-MethodAccess-Control-Request-Headers를 담은 OPTIONS를 보냅니다. 서버가 이를 Access-Control-Allow-Origin·-Methods·-Headers와 2xx로 답하지 않으면 실제 요청은 나가지 않습니다.
  3. 자격증명과 와일드카드 충돌 - 요청이 쿠키나 인증을 보내면(credentials: 'include') Access-Control-Allow-Origin: *는 거부됩니다. 서버는 정확한 오리진을 반환하고 Access-Control-Allow-Credentials: true를 추가해야 합니다.

Diagnose with DechoNet

  • HTTP Check로 서버가 실제로 반환하는 응답 헤더를 확인하세요 — Access-Control-Allow-Origin이 있는지, 어떤 값인지 봅니다.
  • DNS Lookup으로 API 호스트명이 생각하는 그 환경으로 해석되는지 확인하세요. 헤더 누락은 코드 변경이 아니라 오래되거나 잘못된 백엔드인 경우가 많습니다.

Resolution Checklist

  • 응답 헤더를 읽고 Access-Control-Allow-Origin이 존재하는지부터 확인합니다.
  • 있다면 *이거나 요청 오리진(scheme + host + port)과 글자 하나까지 일치하는지 확인합니다.
  • 실패 호출 앞에 OPTIONS가 있으면, 서버가 Access-Control-Allow-Origin·Access-Control-Allow-Methods·Access-Control-Allow-Headers와 2xx로 답하게 합니다.
  • 자격증명 요청에서는 와일드카드를 버리고 특정 오리진을 반환하며 Access-Control-Allow-Credentials: true를 보냅니다.
  • 오리진을 반환할 때 Vary: Origin을 추가해, 공유 캐시가 한 오리진의 허용 헤더를 다른 오리진에 내주지 않게 합니다.
  • Access-Control-Max-Age를 추가해 브라우저가 프리플라이트 결과를 캐시하고 매 호출마다 다시 묻지 않게 합니다.

When to Escalate

  • 애플리케이션에서는 헤더가 맞는데 브라우저에서만 사라진다면, 오리진 앞단의 CDN·리버스 프록시·WAF가 헤더를 떼고 있을 가능성이 큽니다 — 그 계층 담당자에게 넘기세요.
  • 자격증명 요청만 실패한다면, 체인의 모든 홉에서 하드코딩된 Access-Control-Allow-Origin: *를 점검하세요. 체인 어딘가의 와일드카드 하나가 자격증명 경로를 깨뜨립니다.

관련 도구

관련 가이드

가이드 공유

[Ad] Guide Detail Inline
← 전체 가이드 보기