쉬운 설명
브라우저는 기본적으로 'a.com에서 띄운 자바스크립트는 b.com의 API에 함부로 요청하지 못한다'는 규칙(동일 출처 정책, Same-Origin Policy)을 지킵니다. 악성 페이지가 사용자가 로그인된 다른 사이트의 데이터를 마음대로 읽지 못하게 막는 보호 장치입니다.
그런데 실무에선 정당한 이유로 다른 도메인의 API를 호출해야 할 때가 많습니다(예: app.mycompany.com이 api.mycompany.com을 호출). 그때 서버가 '이 도메인에서 오는 요청은 허용한다'를 응답 헤더(Access-Control-Allow-Origin 등)로 명시하면 브라우저가 차단을 풀어 줍니다. 이 약속이 CORS입니다.
동작 흐름은 두 단계입니다. ① 단순한 요청(GET·간단한 POST)은 그냥 보내고, 서버 응답의 CORS 헤더를 보고 허용 여부를 결정. ② 복잡한 요청(PUT·DELETE·커스텀 헤더 등)은 먼저 'OPTIONS' 메서드의 사전 요청(preflight)을 보내, 서버가 허용한다는 응답을 받은 뒤에야 본 요청을 보냅니다. 이 두 단계 덕분에 의도치 않은 변경 요청이 막힙니다.
오해 하나 풀자면, CORS는 '서버를 보호하는' 게 아니라 '브라우저가 사용자를 보호하는' 메커니즘입니다. 그래서 서버에서 'Access-Control-Allow-Origin: *'를 적었다고 API가 안전해지는 게 아닙니다. 인증·인가는 별도로 신경 써야 합니다. 또 같은 사이트에서 같은 사이트의 API를 부르는 경우(예: app과 api가 같은 도메인의 하위 경로)에는 CORS가 필요 없습니다.
자주 만나는 오류와 해결: 'has been blocked by CORS policy' 메시지는 서버가 CORS 헤더를 안 보냈거나, 허용 도메인 목록에 우리 도메인이 없을 때 발생합니다. 해결은 서버에서 Access-Control-Allow-Origin·Allow-Methods·Allow-Headers를 적절히 설정. 단, '*'(모두 허용)는 인증된 요청과 잘 안 어울리니, 정확한 도메인 목록을 적는 게 안전합니다.

비유로 보면
CORS는 회사 건물의 외부 방문자 정책과 비슷합니다. 다른 회사 직원이 우리 회사 사무실을 자유롭게 출입하면 위험합니다. 그래서 건물 정문에서 '어느 회사 사람은 우리 건물의 어느 층까지 와도 좋다'를 명시적으로 허락해야 들어올 수 있습니다. 그 허락 목록이 CORS의 Allow-Origin과 비슷합니다.
어디에서 만나나
프런트엔드와 백엔드가 다른 도메인에 배포된 모든 경우(SPA + API 분리), 외부 API에 자바스크립트로 직접 요청하는 경우(번역·결제·지도 SDK), 브라우저 익스텐션, 모바일 웹뷰. 사실상 모든 현대 웹 개발에서 한 번은 만나는 단어입니다.
작은 예시
프런트엔드(localhost:3000)에서 백엔드(localhost:8080) API를 부르려는 순간 '...has been blocked by CORS policy' 오류를 만나면, 백엔드가 'Access-Control-Allow-Origin: http://localhost:3000' 응답 헤더를 보내도록 설정해야 합니다. 그제야 브라우저가 호출을 허락합니다.
자주 하는 오해
한 줄 정리
CORS는 보안 정책이 아니라 '브라우저가 사용자를 위해 지키는 규칙'입니다. 서버는 신뢰할 도메인을 명시적으로 적고, 인증·인가는 따로 챙겨야 합니다.
