CORS (Cross-Origin Resource Sharing)

고둑·2021년 10월 15일
0

스터디 발표

목록 보기
4/4
post-thumbnail

Cross-Origin Resource Sharing

CORS는 W3C에서 서로 다른 Origin에서 자원(Resource)을 공유할 수 있도록 하기 위해 내놓은 정책을 말한다.
여기서 서로 다른 Origin이라는 것은 도메인 또는 포트가 다르다는 것을 의미하기 때문에 서로 다른 도메인 주소 사이에서 데이터(API 요청과 응답)를 주고받을 수 있도록 하기 위한 정책이라고 말할 수 있다.

CORS가 필요한 이유

CORS가 Cross Origin의 자원을 공유할때 필요한 정책이라는 말은 어떠한 이유로 Cross Origin의 자원을 공유하는 것이 금지되었고 공유를 원할시 예외적으로 CORS를 사용하는 것이라고 유추해볼 수 있다.
Cross Origin의 자원을 공유하는 것이 금지하는 정책은 SOP(Same Origin Policy)라고 한다. 이 정책은 어떤 출처에서 문서 혹은 스크립트가 다른 출처에서 가져온 자원(Resource)과 상호작용 하는 것을 제한하는 보안 방식을 말한다.
즉, SOP를 적용하게 되면 다른 Origin에서는 자원 요청이 불가하기때문에 XSS나 CSRF같은 공격에 대응할 수 있게된다.

하지만 우리가 사용하는 웹은 점점 발전하게 되고 사용자들은 웹에서 더 많은 기능을 원하게 되었다. 그 요구를 충족하려면 동일한 Origin에서의 자원만으로는 한계에 부딪치게 된다. 예를 들어 외부 API를 연동 시켜 사용하는 경우 앱과 API의 Origin의 차이가 생겨 사용이 불가하게된다. 이러한 상황이 계속되자 Cross Origin에서도 자원을 공유해야하는 필요성이 대두되게 되고 이 때문에 SOP의 보안성을 유지하면서 Cross Origin의 자원을 공유할 수 있는 정책인 CORS가 생겨나게 되었다.

기본적인 CORS 동작 방법

  1. HTTP 프로토콜을 사용하여 다른 출처의 리소스를 요청할때 request 헤더의 Origin 필드에 요청을 보내는 출처를 담아서 전송한다.
  2. request가 서버에 도착하게 되면 response를 보내게 되는데, 이때 reponse 헤더의 Access-Control-Allow-Origin 필드에 이 리소스에 접근하는 것이 허용된 출처를 적어 브라우저에게 보낸다.
  3. request에 대한 response를 받은 브라우저는 자신이 보냈던 Origin의 값과 Access-Control-Allow-Origin의 값을 비교하게 되고 이 응답이 유효한 응답인지 아닌지를 결정한다.

이것이 기본적인 CORS 동작방법이다. 하지만 모든 CORS가 이렇게 동작하지는 않는다. CORS가 동작하는 방법은 총 3가지가 존재한다.

CORS 동작 시나리오

1.단순 요청 (Simple Request)


이 방식은 그냥 바로 서버에 본 요청을 전송하게 되고 위에서 설명했던대로 Origin의 값과 Access-Control-Allow-Origin의 값을 비교하여 CORS 위반 여부를 검사하는 방식이다.
단순 요청을 사용하기 위해서는 특정한 동작 요건을 만족하여야 한다.

  • 요청의 메소드는 GET,POST,HEAD 중 한 가지여야 한다.
  • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width 외의 다른 헤더를 사용하면 안된다.
  • 만약 Content-Type를 사용하는 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용된다.

첫번째 조건은 만족하기 쉬우나 2번째 조건부터는 만족하기 매우 힘들어진다.

네이버 웹툰에 접근하기 위한 요청이다. 보이는것과 같이 위에 상기한 헤더 외에도 수 많은 해더를 사용하는 것을 볼 수 있다.
그리고 세번째 조건도 최근에 많이 사용하는 REST API들은 text/xml이나 application/json를 가지기때문에 세번째 조건도 달성이 매우 힘들다.

따라서 대부분의 경우 단순 요청의 동작 요건을 위배하게 되고 프리플라이트 요청을 사용하게 된다.

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


이 방식은 요청을 한 번에 보내지 않고 예비 요청과 본 요청을 나눠서 서버로 전송하게 된다. 본 요청을 보내기 전에 예비로 보내는 요청을 Preflight이라 하고, OPTIONS 메소드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 미리 확인하게 된다.
XSS나 CSRF 같은 공격은 단순히 유저 정보만 가지고도 매우 치명적인 공격 할 수 있기 때문에 미리 전송하는 방식을 사용한 것이다.
이러한 Preflight에 대한 response에 서버는 자신이 허용하고 있는 것과 금지하고 있는것을 보내준다. 이를 기반으로 본 요청을 보내고 CORS 위반 여부를 검사하는 방식이다.

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


인증된 요청을 사용하는 방식이다. 이 방식은 다른 출처 간의 통신에서 좀 더 보안을 강화하고 싶을 때 사용하는 방법이다.
기본적으로 브라우저가 제공하는 비동기 리소스 요청 API인 XMLHttpRequest 객체나 fetch API는 별도의 옵션 없이 브라우저의 쿠키 정보나 인증과 관련된 헤더를 함부로 요청에 담지 않는다. 이때 요청에 인증과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션이다.

credentials에는 3가지 옵션이 있다.

  • same-origin : 같은 출처 간 요청에만 인증 정보를 담을 수 있다.
  • include : 모든 요청에 인증 정보를 담을 수 있다.
  • omit : 모든 요청에 인증 정보를 담지 않는다.

따라서 credentials: 'include'를 사용하게 되면 Cross Origin으로부터 인증정보를 포함한 응답을 받을 수 있게 된다.
Credentialed Request도 동작하기 위해서는 특정한 동작 요건을 만족해야한다.

  • Access-Control-Allow-Origin: * 이면 안되며, 명시적인 URL을 설정하여야 한다.
  • 응답 헤더에는 반드시 Access-Control-Allow-Credentials: true가 존재해야한다.

이상 CORS에 대한 설명을 끝냈다.
이제 다시 중간고사 공부하러 20000

profile
문워킹은 하지말자

0개의 댓글