웹 개발을 하다보면 CORS와 관련된 오류를 종종 만나곤 한다.
특히, CORS 오류는 한 웹사이트에서 다른 웹사이트 서버로 API 요청을 보낼 때 자주 접하는 오류인데, 예를 들어 URL이 "www.aaa.com"인 사이트에서 "www.bbb.com"인 사이트로 API를 통해 정보를 받아오기 위해 HTTP 요청을 보내면, CORS 설정이 없을 경우 에러가 발생한다.
CORS는 Cross Origin Resource Sharing 의 줄임말로, 직역하면 교차 출처 리소스 공유이다.
'리소스 공유' 라는 말은 그럭저럭 이해가 되지만, '교차'와 '출처'라는 말이 생소할 수 있다. 출처라는 말을 이해하기 위해서는 우선적으로 SOP에 대한 이해가 필요하다.
사실상 CORS 가 제안된 원인으로, 직역하면 동일 출처 정책이다.
여기서도 출처(Origin)라는 용어가 계속 사용되는데, 출처(Origin)란 URI 스키마(프로토콜), 호스트 이름(도메인), 포트 번호의 조합을 말한다.
SOP는 자바스크립트 엔진 표준 스펙의 보안 규칙으로 하나의 출처(Origin)에서 로드된 자원(문서 or 스크립트)이 호스트나 프로토콜, 포트번호가 일치하지 않는 자원과 상호작용하지 못하도록 요청 발생을 제한하고, 동일 출처(Same Origin)에서만 접근이 가능한 정책이다. 따라서, SOP는 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여준다.
그런데, 위에서도 설명했지만 현대의 웹 서비스는 서로 다른 출처에서 리소스를 가져오는 경우가 매우매우 많다. 그래서 이를 부분적으로 허용하는 용도로 CORS가 등장한 것이다. 즉, CORS는 SOP를 완화(or 우회)하는 매커니즘으로, 웹페이지 상에서 자바스크립트를 이용하여 XHR(XMLHttpRequest)을 다른 도메인으로 발생시킬 수 있도록 해주고 XHR 기반 cross-origin HTTP 요청을 이용하여 자원을 공유해야 하는 브라우저와 서버 간의 안전한 교차 출처 요청 및 데이터 전송을 지원한다.
CORS 동작 시나리오에는 크게 3가지가 있다.
그 중 웹 서비스에서 가장 빈번하게 사용되는 Preflight Request의 동작방식에 대해서 자세히 알아보자.
Preflight Request는 요청을 예비 요청과 본 요청으로 나눈다. OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 (실제 요청이 전송하기에 안전한지) 확인 작업을 하고, 요청이 가능하다면 실제 요청을 보낸다. Cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 Preflight 요청을 한다.
클라이언트 -> 서버
서버 -> 클라이언트
CORS는 SOP를 완화하기 위해서 제안된 매커니즘이고, SOP는 자바스크립트 엔진 표준 스펙의 보안 규칙이다. 즉, 자바스크립트 엔진을 사용하는 웹 브라우저의 보안 매커니즘인 것이다. 따라서 한 서버에서 로드된 문서 또는 스크립트가 웹 브라우저 엔진에 의해 해석되어 실행될 때, SOP가 적용되고, CORS를 따르지 않는 요청일 경우 에러를 발생시키는 것이다. 따라서, cURL 커맨드나 PostMan 같은 자바스크립트 엔진을 사용하지 않는 경우의 HTTP 요청은 CORS 오류가 발생하지 않는다.