CORS(Cross Origin Resource Sharing; 교차 출처 리소스 공유)란?
- 다른 도메인 간의 리소스 공유 시, 각 도메인의 리소스에 대한 접근 권한을 조정하기 위해 브라우저에서 강제하는 프로토콜입니다.
- 예를 들어, A-domain.com에서 B-domain.com의 리소스에 함부러 접근하여 악용하는 등의 문제점을 막기 위한 보안 조치입니다.
- 하지만 최근들어, 과도한 제약이라는 의견이 대두되고 있기도 하고, 종종 상상하지 못한 곳에서 문제를 발생시켜 개발자들의 복병처럼 느껴지기도 합니다.
📝 주요 개념
✅ 출처(Origin)
-
CORS의 가장 기본이 되는 개념입니다.
-
출처의 예시: https://naver.com:443
-
스키마, 호스트명, 포트로 구성됩니다.
- 스키마: http, https 등
- 호스트명: 도메인 주소, IP 주소 등
- 포트: 0 ~ 65535
-
위 세 가지 구성요소 중 하나만 다르더라도 다른 출처로 간주됩니다.
✅ 단순 요청(Simple Requests)
-
특정 요건을 충족한, 안전한 요청입니다.
- 특정 요건
- 요청 메소드가 GET, HEAD, POST 이어야 합니다.
- 아래와 같은, 표준 헤더만을 사용해야 합니다
- Accept, Accept-Language, Content-Language, Content-Type 등 (참고 - fetch spec)
- Content-Type이 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나이어야 합니다.
-
즉, 흔히 사용하는 POST, Content-Type이 application/json인 경우도 단순요청이 될 수 없습니다.
✅ 사전 요청(Preflight Requests)
-
단순 요청이 아닌 경우, 해당 요청이 안전한지 판단하기 위해 본 요청 전 사전요청을 보냅니다.
-
사전 요청은 OPTIONS 메소드를 사용해 요청되며, 아래의 사항들을 확인합니다.
- 어떤 출처(Origin)을 허용하는가?: Host
- 어떤 메소드를 허용하는가?: Access-Control-Request-Method
- 어떤 헤더를 허용하는가?: Access-Control-Request-Headers
-
요청받은 서버는, 해당 요청에 대해 아래와 같이 답신합니다.
- 해당 출처에서만 사용을 허용한다: Access-Control-Allow-Origin
- 이러한 메소드만 허용한다: Access-Control-Allow-Methods
- 이러한 헤더만 허용한다: Access-Control-Allow-Headers
- 해당 시간동안 같은 조건을 유지하겠다(캐시): Allow-Control-Max-Age
📝 CORS의 작동방식
1. 출처 확인
-
웹 브라우저에서 요청을 보내는 경우, 브라우저는 자동으로 요청 헤더에 'Origin' 헤더를 추가합니다.
-
이는 위에서 설명한 것 과 같이, 스키마, 도메인, 포트번호를 포함합니다.

2-1. 단순요청인 경우 - 종료
2-2. 사전 요청(단순요청이 아닌 경우. 3으로 계속)
-
브라우저는 사전요청을 통해 실제 요청이 안전한 요청인지부터 확인합니다.
-
OPTIONS 메소드를 사용하며, Origin, Method, Header의 사용가능여부를 확인합니다.

- 위 사진은 DELETE 요청에서 Content-Type: application/json 헤더를 실었을 경우의 사전 요청(preflight 요청) 헤더입니다.
- 이 경우, 세 가지 조건에 의해 사전요청이 보내집니다.
- DELETE 메서드를 사용했다.
- Content-Type: application/json을 사용했다.
- X-Test라는 커스텀 헤더를 사용했다.
3. 실제 요청
- 사전요청이 성공하면, 브라우저는 서버에서 서용하는 Origin, Header, Method를 알게됩니다.
- 이를 바탕으로 실제 요청이 적절한지 확인하고, 적절하지 못한 경우 CORS 에러를 표시합니다.
- 적절한 경우, 실제 요청을 서버에 전달하고 응답을 받습니다.
4. 응답 처리 - 종료
- 마지막으로, 실제 요청 결과의 Access-Control-Allow-Origin 헤더를 확인한 후, 현재의 Origin에서 사용 가능하다면(전체 허용 - * 이거나 포함된 경우)요청은 성공적으로 처리되고, 자원을 사용 할 수 있게 됩니다.
🖥️ 간단한 예제 코드
express 앱에서, 위에서 다루었던 요청을 브라우저에서 사용 가능하게 하려면 아래와 같은 설정이 필요합니다.
app.options('/json-cors', (req, res) => {
res.set({
'Access-Control-Allow-Origin': 'http://localhost:3000',
'Access-Control-Allow-Methods': 'DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, X-Test',
});
res.sendStatus(204);
});
app.delete('/json-cors', (req, res) => {
...
res.set({
'Access-Control-Allow-Origin': 'http://localhost:3000',
})
...
});
CORS 테스트 프로젝트 - 링크

Express와 ejs 템플릿을 사용한 간단한 CORS 테스트 프로젝트입니다.
👍 결론
결과적으로 CORS는 웹 브라우저에서 보안성을 지키기 위해 적절히 사용해야할 하나의 도구입니다.
따라서 우리 개발자들은, 이를 적절히 이해하고 활용할 필요가 있고, 이를 통해 보안성을 지키면서도, 자원 공유간에 불필요한 충돌을 막고, 리소스 낭비를 최소화 할 수 있습니다.