- CORS 간단 요약
- 하나의 클라이언트는 다른 사이트에서 리소스를 요청하려면, 일반 요청에 비해 지켜야 할 것이 있다. CORS 요청은 특별한 헤더가 추가된다.
- 다른 사이트의 구분은 프로토콜, 도메인, 포트로 한다.
- 다른 사이트 리소스 요청은 안전한 요청과 안전하지 않은 요청 두가지로 분류하고, 안전하지 않은 요청의 경우 브라우저가 preflight 요청을 추가적으로 하게된다.
- 다른 사이트 리소스 요청을 하기 위해서는 서버에서 허용을 해주어야하고, 이에 맞추어 클라이언트에서도 대응하여야 한다. (대부분의 책임은 서버쪽이다.)
- 쿠키를 사용하기 위해선 credential 관련 옵션도 서버에서 허용해주어야 한다.
- SOP : Same-Origin-Policy
- Origin
하나의 클라이언트는 하나의 Origin 에서만 리소스를 요청하도록 하는 정책, 아무 것도 설정하지 않을 시, 기본 정책
Origin 은 브라우저가 request 시에 넣는 헤더 중 하나로, 요청을 보내는 웹 사이트의 프로토콜, 도메인, 포트번호를 보내게 된다.
Origin 의 구분은 URL의
Scheme
(프로토콜), Host
(도메인), Port
(포트번호)으로 한다.Origin의 비교는 브라우저가 한다. 브라우저에 따라서 비교로직이 다를 수 있다.
- 예전에 javascript 에서 request 를 보내던 방법
- form
- script
- 안전한 메소드:
GET
,POST
,HEAD
메소드 - 안전한 헤더:
Accept
,Accept-Language
,Content-Language
,
fetch api 를 제공해 주기 전 javascript 에서는 다른 origin 에 요청을 보낼 때, 다음과 같은 방법을 사용했다. 다른 origin 에 요청하는 것 자체가 허용되지 않았었기 때문이다.
form
은 어디에든 데이터를 전송할 수 있었기 때문에, form
태그와 iframe
태그를 이용해서 우회script
태그의 src
속성은 도메인에 대한 제약이 없었기 때문에, 이를 통해 우회위 두가지 방법을 사용한 요청은 안전한 요청으로, 다음과 같은 제한사항이 있었다.
Content-Type
헤더 값이 application/x-www-form-urlencoded
, multipart/form-data
, text/plain
인 경우두 조건을 모두 만족해야만 한다.
- CORS : Cross-Origin-Resource-Sharing
- 안전한 요청
- 안전하지 않은 요청
CORS 요청은 앞서 설명한 안전한 요청과 안전하지 않은 요청이 구분되어 요청 방식이 다르게 동작한다.
안전한 CORS 요청 시, 브라우저는 origin 을 알려주는
Origin
헤더를 추가해서 서버에 전송한다. 그러면, 서버는 Access-Control-Allow-Origin
이 있는지 확인해서, 서버가 해당 origin 의 요청을 허용하는지 확인한다. 일반적으로 요청의 Origin
헤더의 값과 응답의 Access-Control-Allow-Origin
의 값이 같거나 *
이면 허용한다고 본다. 이렇게 CORS 요청이 이뤄진 경우, 자바스크립트는 기본적으로 안전한 응답 헤더에만 접근 할 수 있다.안전하지 않은 요청 시, 브라우저는 preflight 요청을 먼저 보내게 된다. 이는 http 의
OPTION
메소드로 요청하며, Access-Control-Request-Method
헤더와 Access-Controll-Request-Headers
헤더를 통해 안전하지 않은 요청의 메소드와 헤더 종류가 서버에서 허용하는 것인지 확인한다.이 preflight 요청의 응답으로 다음과 같은 것을 제공받는다.
Access-Control-Allow-Origin
, Access-Control-Request-Method
, Access-Controll-Request-Headers
, Access-Control-Max-Age
Max-Age 헤더를 통해 preflight 요청을 브라우저에서 캐시하고, 해당 기간동안 preflight 요청을 생략한다.
- 자격증명
자바스크립트로 CORS 요청을 보내면, 기본적으로 쿠키나 http 인증 같은 자격 증명(Credential)이 함께 전송되지 않는다.
하지만, 요즘은 쿠키를 아주 많이 사용하기 때문에, credential 한 정보를 추가하고 싶다면 다음과 같이 해야한다.
fetch('url', { credentials: 'include' }
위와 같이 요청을 하면, 쿠키가 같이 url 에 전송되며, 응답에도
Access-Control-Allow-Credentials: true
이 추가되어 온다.- CORS 에러
즉, CORS 에러는 브라우저가 내는 에러이며, Origin 이 다른 요청을 하는 것이 이상하다고 느껴서 내는 것이다. (이거 위험한 요청인 것 같으니 브라우저에서 막아야겠다! 하는 것)