WIL (Weekly I Learned) 220808-2208014

BOSEUL KIM·2022년 8월 14일
0

TIL / WIL

목록 보기
8/9

CORS 란?

  • CORS는 Cross-Origin Resource Sharing 의 약자로 교차 출처 리소스 공유로 번역될 수 있는데, 브라우저에서 다른 출처의 리소스를 공유하는 방법입니다.

URL 구조

다른 출처의 출처가 무엇인지 살펴봐야 하는데, 출처가 무엇인지 알기 위해서 먼저 URL의 구조를 살펴보아야 합니다. URL 구조는 아래 그림과 같습니다.

프로토콜의 HTTP는 80번, HTTPS는 443번 포트를 사용하는데, 80번과 443번 포트는 생략이 가능합니다.

출처(Origin)란?

출처(Origin)란 URL 구조에서 살펴본 Protocol, Host, Port를 합친 것을 말합니다. 브라우저 개발자 도구의 콘솔창에 location.origin을 실행하면 출처를 확인할 수 있습니다.

같은 출처 VS 다른 출처

같은 출처인지 다른 출처인지 이해를 돕기 위해 예제를 하나 살펴보도록 하겠습니다. 현재 웹페이지의 주소가 https://velog.io/@keembogeul 일 때 같은 출처인지 다른 출처인지 아래 테이블과 같은 결과를 얻을 수 있습니다.

URL 결과 이유
https://velog.io/@keembogeul/about 같은 출처 Protocol, Host, Port 동일
https://velog.io/@keembogeul/about?q=work 같은 출처 Protocol, Host, Port 동일
https://velog.io/@keembogeul/about#work 같은 출처 Protocol, Host, Port 동일
http://velog.io/@keembogeul 다른 출처 Protocol 다름
http://velog.io/@keembogeul:81/about 다른 출처 Port 다름
https://velog.io/@keemboseul 다른 출처 Host 다름

동일 출처 정책(Same-Origin Policy) 이란?

Postman으로 API를 테스트하거나, 다른 서버에서 API를 호출할 때는 멀쩡히 잘 동작하다가 브라우저에서 API를 호출할 때만 CORS policy 오류가 발생해서 당혹스러울 때가 있으셨을 수도 있습니다. 그 이유는 브라우저가 동일 출처 정책(Same-Origin Policy, SOP) 를 지켜서 다른 출처의 리소스 접근을 금지하기 때문입니다. 하지만 실제로 웹페이지는 상당히 자주 다른 출처의 리소스를 사용해야 합니다. 예를 들어 https://velog.io/@keembogeul라는 도메인 주소를 사용하는 웹페이지에서 https://velog-api.io/@keembogeul라는 API서버로 데이터를 요청해서 화면을 그린다면 이 웹페이지는 동일 출처 정책을 위반한 것이 됩니다.

동일 출처 정책의 장점

동일 출처 정책을 지키면 외부 리소스를 가져오지 못해 불편하지만, 동일 출처 정책은 XSS나 XSRF 등의 보안 취약점을 노린 공격을 방어할 수 있습니다. 하지만 현실적으로는 외부 리소스를 참고하는 것은 필요하기 때문에 외부 리소스를 가져올 수 있는 방법이 존재해야 합니다. 외부 리소스를 사용하기 위한 SOP의 예외조항이 CORS입니다.

CORS 동작원리

CORS의 동작 방식은 단순 요청 방법과 예비 요청을 먼저 보내는 방법. 2가지 방법이 있습니다.

Simple request

단순 요청 방법은 서버에게 바로 요청을 보내는 방법입니다. 아래 그림은 자바스크립트에서 API를 요청할 때 브라우저와 서버의 동작을 나타내는 그림입니다.

단순 요청은 서버에 API를 요청하고, 서버는 Access-Control-Allow-Origin 헤더를 포한한 응답을 브라우저에 보냅니다.
브라우저는 Acess-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단합니다.

Simple request 조건

서버로 전달하는 요청(request)이 아래의 3가지 조건을 만족해야 서버로 전달하는 요청이 단순 요청으로 동작합니다.

  • 요청 메소드(method)는 GET, HEAD, POST 중 하나여야 합니다.
  • 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번, 3번 조건은 까다로운 조건입니다. 2번 조건은 사용자 인증에 사용되는 Authorization 헤어도 포함되지 않아 까다로운 조건이며, 3번 조건은 많은 REST API들이 Content-Type으로 application/json을 사용하기 때문에 지켜지기 어려운 조건입니다.

Preflight request

Preflight 요청은 서버에 예비 요청을 보내서 안전한지 판단한 후 본 요청을 보내는 방법입니다. 아래 그림은 Preflight 요청 동작을 나타내는 그림입니다.

GET, POST, PUT, DELETE 등의 메소드로 API를 요청했는데, 크롬 개발자 도구의 네트워크 탭에 OPTIONS 메소드로 요청이 보내지는 것을 보신 적 있으시다면 CORS를 경험하셨던 것입니다. Preflight 요청은 실제 리소스를 요청하기 전에 OPTIONS라는 메소드를 통해 실제 요청을 전송할지 판단합니다.

OPTIONS 메소드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보냅니다. 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단합니다.

CORS 에러 해결 방법

앞에서 이야기 한 CORS 동작 원리를 보면, 서버에서 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보내는 방식으로 CORS 에러를 해결할 수 있습니다. 프론트엔드 개발자가 CORS 에러를 확인했다면, 서버에 Access-Control-Allow-Origin 등 CORS를 해결하기 위한 몇 가지 응답 헤더를 포함해 달라고 요청해야 합니다.

Node.js의 Express는 cors라는 서드 파트 미들웨어를 지원합니다. 이 라이브러리에서 CORS 응답 헤더를 추가해 주기 때문에, 개발자가 별도의 CORS 응답 헤더를 추가하지 않아도 됩니다. 다른 프레임워크에서도 CORS를 해결해주는 라이브러리가 존재합니다.

출처: https://beomy.github.io/tech/browser/cors/

0개의 댓글