본문 바로가기
Network

CORS에 대한 이해

by eoruadl 2023. 2. 25.

CORS(Cross-Origin Resource Sharing)를 이해하기 위해 이번 포스팅을 진행하려고 한다.

 

CORS는 교차 출처 리소스 공유라는 의미로 여기서 '교차 출처'를 다른 의미로 해석하면 '다른 출처' 라고 생각할 수 있다. 즉 다른 출처간의 리소스를 공유하는 정책을 의미한다. 

 

먼저, 출처(Origin)에 대해 자세하게 알아보자.

 

Origin (출처)

Origin은 URL에서 프로토콜, 도메인, 포트번호를 합친 것을 말한다. 서버의 위치를 찾아가기 위해 필요한 가장 기본적인 것들을 합쳐놓은 것이다.

https://techgm28.tistory.com:80/posts/2

다음의 URL을 살펴보면 https:// 이부분이 프로토콜(scheme)에 해당되며 techgm28.tistory.com이 도메인, :80 은 포트번호에 해당된다. 이 때 포트번호는 생략이 가능하다. 기본적으로 http, https 프로토콜의 기본 포트번호가 정해져있기 때문이다. 만약 포트번호가 명시되어 있다면 포트번호까지 다 일치하는 출처만이 같은 출처로 인정된다.

 

SOP(Same-Origin Policy)

이제 SOP와 CORS의 관계에 대해 알아보자. SOP는 동일 출처 정책이라고 하며 다른 Origin으로 요청을 보낼 수 없도록 금지하는 브라우저의 기본 보안 정책이다. 동일한 Origin으로만 요청을 보낼 수 있도록 하는 것이다. 원래는 다른 출처로 요청을 보내는 것이 불가능 했었는데 기술의 발달로 인해 다른 Origin으로 요청을 보내 데이터를 주고 받아야하는 경우가 생겨 SOP는 예외 사항을 가지게 된다. 

 

RFC6454을 확인해보면 <script> 로 자바스크립트를 실행하는 경우, 이미지를 렌더링하는 경우, <link> 로 스타일시트 파일을 불러오는 경우, HTML 문서를 화면에 보여주는 경우에는 다른 Origin으로의 요청을 허용한다고 한다. 그리고 CORS 정책을 지키는 요청의 경우에도 다른 Origin으로의 요청을 허용한다는 내용이 있다.

 

이 정책을 통해 확인할 수 있는 것은 CORS는 다른 Origin으로 요청을 보내기 위해지켜야하는 정책으로, 다르게 해석하면 SOP에 의해 막히는 요청을 안막히게 도와주는 정책이다.

 

또 하나 확인해야할 점은 CORS는 브라우저 정책이다. 그래서 서버는 요청을 받으면 CORS를 지켰든 말든 응답을 해준다. 즉 서버간의 요청에 대해서는 에러가 발생하지 않는다. 브라우저에서 자신이 보낸 요청 또는 서버가 보낸 응답이 CORS 정책을 지켰는지 확인하여 응답을 버릴지 말지를 결정한다. 즉 서버간의 통신에서는 이러한 정책이 적용되지 않는다는 것을 확인할 수 있다.

 

CORS 동작 원리

CORS의 기본적인 동작원리를 알아보면, 브라우저는 다른 Origin으로 요청을 보낼 때 Origin 헤더에 자신의 Origin을 설정하고, 서버로 부터 응답을 받으면 응답의 Access-Control-Allow-Origin 헤더에 설정된 Origin의 목록에 요청의 Origin 헤더값이 포함되는지 검사하는 것이다. 즉, CORS 요청을 위해서는 서버에서 응답의 Access-Control-Allow-Origin 헤더에 허용되는 Origin의 목록 혹은 와일드카드(*)를 설정해주면 된다. 이것이 기본적인 CORS 정책이다.

 

조금 더 깊게 생각해보면 CORS 요청은 세가지 유형으로 나눌 수 있다.

 

1. 단순 요청(Simple Request)

단순 요청 이름과는 다르게 조건이 까다롭다.

  • 메소드가 GET, HEAD, POST 중 하나여야 한다.
  • User Agent가 자동으로 설정한 헤더를 제외하면, 아래와 같은 헤더들만 사용 가능
    • Accept
    • Accept-Language
    • Content-Language
    • Context-Type
    • DPR
    • Downlink (en-US)
    • Save-Data
    • Viewport-Width
    • Width
  • Content-Type 헤더에는 아래와 같은 값들만 설정 가능
    • application/x-www-form-urlencode
    • multipart/form-data
    • text/plain
  • ...

위의 조건을 만족하는 단순 요청은 안전한 요청으로 취급되며 단 한번의 요청만을 전송한다.

다른 Origin으로 요청을 보낼 때 Origin 헤더에 자신의 Origin을 설정하고, 서버로부터 응답을 받으면 응답의 Access-Control-Allow-Origin 헤더에 설정된 Origin의 목록에 요청의 Origin 헤더값이 포함되어 있는지 확인한다.

 

2. 프리플라이트 요청 (Preflight Request)

단순 요청의 조건을 벗어나는(안전하지 않은) 요청의 경우, 서버에 실제 요청을 보내기 전에 예비 요청에 해당하는 프리플라이트 요청을 먼저 보내서 실제 요청이 안전한지 먼저 확인한다. 만약 안전한 요청이라고 확인되면 그 때서야 실제 요청을 보낸다. 따라서 총 두 번의 요청을 보낸다.

 

프리플라이트 요청의 특징

  • 메소드로 OPTIONS를 사용
  • Origin 헤더에 자신의 Origin을 설정
  • Access-Control-Request-Method 헤더에 실제 요청에 사용할 메소드를 설정
  • Access-Control-Request-Header 헤더에 실제 요청에 사용할 헤더를 설정

서버는 이러한 프리플라이트 요청에 다음과 같은 특징을 가진 응답을 제공

  • Access-Control-Allow-Origin 헤더에 허용되는 Origin들의 목록 혹은 와일드카드(*)를 설정
  • Access-Control-Allow-Methods 헤더에 허용되는 메소드들의 목록 혹은 와일드카드(*)를 설정
  • Access-Control-Allow-Headers 헤더에 허용되는 헤더들의 목록 혹은 와일드카드(*)를 설정
  • Access-Control-Max-Age 헤더에 해당 프리플라이트 요청이 브라우저에 캐시 될 수 있는 시간을 초 단위로 설정

브라우저는 이러한 응답의 정보를 자신이 전송한 요청의 정보와 비교하여 실제 요청의 안정성을 검사한다.

만약 안정성 검사를 통과하면 실제 요청을 서버에 보낸다. 실제 요청을 보낼 때는 Access-Control-Request-xxx 와 같은 헤더는 보내지 않는다.

 

3. 인증 정보를 포함한 요청 (Credentialed Request)

쿠키(Cookie) 혹은 Authorization 헤더에 설정하는 토큰 등과 같은 인증 정보를 함께 보내야 하는 경우이다.

 

먼저, 인증 정보를 보내기 위해서는 클라이언트 단에서 요청 시 별도의 설정이 필요하다.

Ajax 요청을 위해 어떠한 어떠한 도구를 사용하느냐에 따라 달라진다. 만약 XMLHttpRequest, jQuery의 Ajax 또는 axios를 사용하면 withCredentials 옵션을 true로 설정해줘야 한다. 반면, fetch API를 사용했다면 credentials 옵션을 include 로 설정해줘야한다. 이러한 별도의 설정을 해주지 않으면 쿠키 등의 인증 정보는 절대 자동으로 전송되지 않는다.

 

이러한 설정을 통해 인증 정보를 포함시켰다면 서버에 보내는 요청은 인증 정보를 포함한 요청이 된다. 그리고 서버는 이러한 요청에 대해 일반적인 CORS 요청과는 다르게 대응해줘야한다. 응답의 Access-Control-Allow-Origin 헤더가 와일드카드(*)가 아닌 분명한 Origin으로 설정되어야 하며, Access-Control-Allow-Credentials 헤더는 true로 설정되어야 한다. 그렇지 않으면 브라우저에 의해 응답이 거부된다.

 

[참고]

https://it-eldorado.tistory.com/163

 

[Web] CORS (Cross Origin Resource Sharing) 이해하기

이번 포스팅에서 다룰 내용은 바로 CORS(Cross Origin Resource Sharing)이다. 웹 개발자라면 한 번쯤은 CORS와 관련하여 콘솔에 뜨는 빨간 글씨의 에러 때문에 짜증 났던 적이 있을 것이다. 하지만 CORS 정책

it-eldorado.tistory.com

https://evan-moon.github.io/2020/05/21/about-cors/

 

CORS는 왜 이렇게 우리를 힘들게 하는걸까?

이번 포스팅에서는 웹 개발자라면 한번쯤은 얻어맞아 봤을 법한 정책에 대한 이야기를 해보려고 한다. 사실 웹 개발을 하다보면 CORS 정책 위반으로 인해 에러가 발생하는 상황은 굉장히 흔해서

evan-moon.github.io

 

'Network' 카테고리의 다른 글

RESTful API  (0) 2023.02.23
URI URL URN  (0) 2023.02.21
HTTP 상태코드  (0) 2023.02.19
HTTP란?  (0) 2023.02.18

댓글