CORS(교차 출처 리소스 공유)

최건우·2023년 1월 31일
0

목록 보기
1/1

교차 출처 리소스 공유(Cross-Origin Resource Sharing)

개념

  • 서버가 자신이 속한 곳(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가 동작하는 메커니즘은 다음과 같다.

요청(1): 단순 요청

단순 요청(simple requests)은 CORS Preflight를 트리거하지 않는다. 단순 요청이라 함은, 아래의 조건을 모두 만족하는 경우를 뜻한다.

  1. GET, POST, HEAD를 사용한 요청
  2. 안전한 헤더(임의의 헤더가 아닌, 자동으로 설정되는 웹 표준 헤더)
    1. Accept
    2. Accept-Language
    3. Content-Language
    4. Conent-Type 중 값이 아래에 해당하는 것
      1. application/x-www-form-urlencoded
      2. multipart/form-data
      3. text/plain

요청 헤더

교차 출처 요청을 보낼 때, 브라우저는 항상 Origin이라는 헤더를 요청에 추가한다. 이는 요청을 보내는 도메인을 의미한다. 예를 들어 https://foo.examplehttps://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

그 외에 다음과 같은 '안전한 응답 헤더'들이 포함된다.

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma
    만약 안전하지 않은 응답 헤더들을 추가하려면, 'Access-Control-Expose-Headers' 응답 헤더를 추가하고 추가할 안전하지 않은 응답 헤더들을 명시해 줘야 한다.

요청(2): Preflight 요청

단순 요청에 해당하지 않는 경우는 안전하지 않은 요청으로 간주된다. 오래된 브라우저에서는 이와 같은 요청은 거절되기도 한다. 이같은 상황을 방지하고자, 브라우저는 ‘안전하지 않은’ 요청을 서버에 바로 보내지 않고 ‘preflight’ 요청이라는 일종의 사전 요청을 서버에 보내 권한이 있는지를 확인한다.

단순 요청의 경우와 달리, 브라우저가 OPTIONS 메서드를 이용해 다른 도메인의 리소스로 HTTP 요청을 보내서, 해당 리소스로 실제 요청을 보내도 안전한지를 확인하다. cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와 같이 미리 전송(preflighted)하는 것이다.

Preflight 요청 헤더

Preflight 요청은 OPTIONS 메서드 다음 두 헤더가 함께 들어가며, 본문은 비어있다.

  • Access-Control-Request-Method: 안전하지 않은 요청에서 사용하는 메서드 정보가 담겨있다.
  • Access-Control-Request-Headers: 안전하지 않은 요청에서 사용하는 헤더 목록이 담겨있고, 각 헤더는 쉼표로 구분된다.

Preflight 응답 헤더

서버는 Preflight 요청에 대해, 본문은 비어있고 status code를 200으로 하여 다음과 같은 헤더를 브라우저에 응답한다.

  • Access-Control-Allow-Origin: '*' 이거나, 요청을 보낸 오리진(예: https://javascript.info)
  • Access-Control-Allow-Methods: 허용된 HTTP 메서드 정보가 담겨있음.
  • Access-Control-Allow-Headers: 허용된 헤더 목록이 담겨있음.
  • Access-Control-Max-Age: 퍼미션 체크 여부를 몇 초간 캐싱해 놓을지를 명시한다. 이렇게 퍼미션 정보를 캐싱해 놓으면, 브라우저는 일정 기간 동안 preflight 요청을 생략하고 안전하지 않은 요청을 보낼 수 있다.

사전 요청에 대한 응답이 이렇게 오지 않으면, 본 요청을 보낼 수 없다.
또한, 교차 출처 요청을 허락하지 않는 서버일 경우, prefligh 요청은 에러가 발생한다.

실제 요청 헤더

preflight request가 완료되면 실제 요청을 전송한다. 안전한 요청이 이뤄질때의 절차와 동일하며, 마찬가지로 Origin 헤더가 붙는다.

실제 응답 헤더

preflight 요청이 성공했더라도 Access-Control-Allow-Origin 헤더를 반드시 붙여서 응답한다.





출처

profile
부족한 경험을 채우기 위한 나만의 기록 공간

0개의 댓글