서버가 자신이 속한 곳(origin)과 다른 어떠한 출처(origin)(도메인, 스키마, 포트 등)에서 실행 중인 웹 애플리케이션이 서버의 출처에 있는 특정 리소스에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 기제.
브라우저는 교차 출처 자원을 제공하는 서버에 자원을 요청하기 전에 앞서 preflight 요청
을 보내서, '이 서버가 실제 요청을 허용해 줄 수 있는지'를 확인한다. 이때, 브라우저는 실제 요청에 사용될 HTTP 메서드와 헤더 정보를 보낸다.
예시: https://domain-a.com
의 프론트엔드 자바스크립트 코드가 https://domain-b.com/data.json
에 요청하는 경우
보안상의 이유로, 브라우저는 교차 출처 HTTP 요청을 제한한다.
XMLHttpRequest, Fetch API는 동일 출처 정책(same-origin-policy)를 따르는데, 이는 이러한 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 요청할 수 있으며, 다른 출처의 리소스를 불러오려면 올바른 CORS 헤더를 포함한 응답을 반환해야 함을 의미한다.
과거부터 존재했던 이 보안상 제약은, 어느 순간부터 보다 강력한 기능을 원하는 웹 개발자들이 만든 트릭에 의해 우회되기 시작했다. 이를 테면 어디든 데이터를 보낼 수 있는 <form>
안에 <iframe>
을 넣는다거나, <script>
태그의 src 속성값에 도메인 제약이 없는 점을 이용해 보안 규칙을 어기지 않으면서도 양방향으로 데이터를 전달했다.
HTTP 요청 메서드가 처음 등장했을 때는 교차 출처 요청이 불가했지만, 서버에서 명시적으로 교차 출처 요청을 허가하는 특별한 헤더를 전송받았을 때만 가능하도록 제한적으로 허용하게 되었다.
교차 출처 요청을 허용하기로 합의한 웹 애플리케이션과 서버에 대해, 요청 ~ 응답 간에 CORS가 동작하는 메커니즘은 다음과 같다.
단순 요청(simple requests)은 CORS Preflight를 트리거하지 않는다. 단순 요청이라 함은, 아래의 조건을 모두 만족하는 경우를 뜻한다.
교차 출처 요청을 보낼 때, 브라우저는 항상 Origin
이라는 헤더를 요청에 추가한다. 이는 요청을 보내는 도메인을 의미한다. 예를 들어 https://foo.example 이 https://bar.other 의 컨텐츠를 호출하려고 한다면, 요청 헤더에는 Origin: https://foo.example
이라는 내용이 반드시 들어간다. 서버는 이를 통해 요청의 발송지를 식별한다.
서버는 이에 대한 응답으로Access-Control-Allow-Origin
헤더를 다시 전송한다. 만약 모든 도메인에서의 요청을 허용하려면 *
를, 특정 도메인만 허용한다면 해당 도메인값을 쓴다. 예를 들면 응답 헤더의 Access-Control-Allow-Origin 헤더의 형태는 다음과 같다.
Access-Control-Allow-Origin: *
(또는)
Access-Control-Allow-Origin: https://foo.example
그 외에 다음과 같은 '안전한 응답 헤더'들이 포함된다.
단순 요청에 해당하지 않는 경우는 안전하지 않은 요청으로 간주된다. 오래된 브라우저에서는 이와 같은 요청은 거절되기도 한다. 이같은 상황을 방지하고자, 브라우저는 ‘안전하지 않은’ 요청을 서버에 바로 보내지 않고 ‘preflight’ 요청이라는 일종의 사전 요청을 서버에 보내 권한이 있는지를 확인한다.
단순 요청의 경우와 달리, 브라우저가 OPTIONS
메서드를 이용해 다른 도메인의 리소스로 HTTP 요청을 보내서, 해당 리소스로 실제 요청을 보내도 안전한지를 확인하다. cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와 같이 미리 전송(preflighted)하는 것이다.
Preflight 요청은 OPTIONS
메서드 다음 두 헤더가 함께 들어가며, 본문은 비어있다.
서버는 Preflight 요청에 대해, 본문은 비어있고 status code를 200으로 하여 다음과 같은 헤더를 브라우저에 응답한다.
사전 요청에 대한 응답이 이렇게 오지 않으면, 본 요청을 보낼 수 없다.
또한, 교차 출처 요청을 허락하지 않는 서버일 경우, prefligh 요청은 에러가 발생한다.
preflight request가 완료되면 실제 요청을 전송한다. 안전한 요청이 이뤄질때의 절차와 동일하며, 마찬가지로 Origin
헤더가 붙는다.
preflight 요청이 성공했더라도 Access-Control-Allow-Origin
헤더를 반드시 붙여서 응답한다.
출처