개념
- Cross Origin Resource Sharing
- 보안 상의 이유로 모든 웹사이트는 기본적으로 SOP(Same-Origin Policy)를 따른다. 다시 말해, 같은 출처에 대한 데이터 요청은 항상 허락되지만, 다른 출처로 데이터를 요청할 경우 특별한 규칙에 따라 허락을 받아야 한다.
- 해당 규칙이 CORS로, 다른 출처에 데이터를 요청할 때 CORS를 지키지 않으면 서버가 정상적으로 응답하더라도 브라우저가 응답을 파기하고 클라이언트에 에러를 던진다.
출처
- CORS에서 이야기하는 출처는 URI를 구성하는 요소 중 Scheme, Host, Port를 말한다.
- 3가지 중 하나라도 다른 경우 다른 출처로 간주하며, 포트 번호의 경우 따로 명시되지 않은 경우 HTTP/HTTPS의 기본 포트번호를 기준으로 한다.
- 출처의 구성 요소
- Scheme
http://
, https://
와 같은 프로토콜. http와 https는 다른 프로토콜이기 때문에, 호스트가 같더라도 서로 다른 출처로 인식하여 CORS에러가 발생할 수 있다.
- Host
www.naver.com
과 같이, 다른 웹사이트와 구분되는 독립적인 이름. 우리가 흔히 주소라고 부르는 부분을 말하며, 뒷부분의 파라미터와 쿼리스트링 등은 포함하지 않는다.
- Port
- 생략되는 경우가 많으며, 명시할 경우 호스트 뒤에 붙는다.
- 예:
https://www.pereng.com:8000
- http의 기본 포트번호는
:80
, https의 기본 포트번호는 :443
이다.
누가 확인하지?
- CORS는 브라우저에서 판단하고 적용한다. 클라이언트와 서버는 자신이 누구인지, 어떤 요청을 허락할 것인지를 요청 헤더에 담아 전송하고, CORS위반 여부는 브라우저가 판단한다.
- 따라서 CORS를 위반한 경우 서버에서는 정상적으로 처리했더라도 브라우저에서 응답을 파기한다.
- 서버 로그에는 정상적인 통신으로 기록된다는 의미
- 브라우저마다 판단 기준이 조금씩 다를 수 있으며, 특히 IE의 경우 출처 판단 시 포트 번호를 무시한다.
CORS 관점에서 보는 3가지 통신 방법
- Preflight
- 브라우저가 서버에 예비 요청을 보낸다
- 예비 요청에 대해, 서버는 어떤 것들이 허용되고 금지되는지에 대한 정보를 응답 헤더에 담아 보낸다.
- origin, credential, method 등
- 브라우저는 예비 요청과 그에 대한 서버의 응답을 비교하여 안전하다고 판단될 경우 본 요청을 서버로 보낸다
- 이후 서버가 응답하면 브라우저는 응답 데이터를 클라이언트에 넘겨준다
- Simple Request
- 브라우저는 예비 요청 없이 서버에 바로 본 요청을 보내고, 응답 헤더의 내용을 바탕으로 CORS 정책 위반 여부를 파악하여 처리한다
- 예비 요청이 없다는 점을 제외하고, 1번과 로직이 같다
- 제약 조건이 까다로워, 실제로 사용되는 일이 드물다
- 사용 가능한 method 제한,
- 사용 가능한 header 제한,
- 사용 가능한 Content-type 제한
- Credentialed Request
- 요청 헤더에 Credentials를 추가하여 요청을 보낼 때 쿠키와 같은 인증 정보를 함께 전송
- Same-origin: 같은 출처에 보낼 때만 인증 정보 전송
- Include: 모든 요청에 대해 인증 정보 전송
- Omit: 모든 요청에 인증 정보를 담지 않음
- 인증 정보가 담긴 상태에서 다른 출처로 리소스를 요청할 경우 기존 CORS 룰에 새로운 규칙을 2개 추가함
- 서버측에서
Access-Control-Allow-Credentials: true
를 꼭 사용해야 함
- 서버측에서
Access-Control-Allow-Origin
에 명확한 출처를 명시해야 함
- 보안 상의 이슈로
*
를 사용할 수 없음
CORS 이슈를 해결하는 방법
서버
Access-Control-Allow-Origin
설정하기
- 가급적
*
보다는 구체적인 출처를 명시할 것(보안 이슈)
- 클라이언트에서 요청에
Credentials: include
옵션을 사용한 경우, *
를 사용하면 CORS 에러 발생
Access-Control-Allow-Credentials: true
확인하기
- 클라이언트에서
Credentials: include
옵션을 사용한 경우, 그에 대해 해당 옵션을 사용하지 않으면 CORS 에러가 발생함.