CORS와 Axios, fetch를 알아보자

쭌로그·2025년 3월 8일
1
post-thumbnail

서론

사내 프로젝트 진행 중 PM으로부터 "다른 플랫폼 사이트를 이동하기 전에 해당 사이트가 접근이 허용이 되었는지, 방화벽은 열려있는지 확인할 수 있었으면 좋겠다."라는 의견을 받았습니다.
처음에는 window.open의 postMessage 메서드를 사용할까 고민했지만 Nifi, 타 부서 사이트 등 Response Message를 받을 수 있는 환경이 아니여서 다른 방법을 모색했습니다.
그러던 중 fetch 메서드의 no-cors 옵션을 사용하면 Cors 없이 해당 사이트에 요청을 보낼 수 있다는 점을 알게 되었고 해당 옵션을 사용하여 로직을 구현할 수 있었습니다.
해당 내용을 학습하면서 XMLHttpRequest와 fetch 메서드, simple request에 대해 학습하게 되었고 학습한 내용을 블로그에 정리하고자합니다.

리소스 요청

클라이언트와 서버간의 통신은 리소스를 요청하기 위해 존재합니다. 리소스 요청에 대한 정책은 SOP와 CORS가 있습니다.

1. SOP(Same-Origin-Policy)

SOP란 "같은 출처에서만 리소스를 공유한다"라는 정책입니다. 다른 출처 마음대로 리소스를 가져갈 수 있다면 CSRF나 XSS를 통해 정보를 탈취하여 보안의 위험성을 초래합니다. 이를 방지하기 위해서 같은 출처에서만 정보를 공유할 수 있도록 한다면 클라이언트와 서버가 정보 공유가 불가능해집니다.

이를 해결하고자 특정 정책을 지킨다면 다른 출처에서도 리소스를 가져갈 수 있도록 허용하는데 이 정책 중 하나가 CORS 정책입니다.

* 같은 출처란?

같은 출처란 URL에서 Protocol, Host, Port 3가지가 동일할 때 같은 출처라고합니다.

cors(Cross-Origin-Resource Sharing)

cors(교차 출처 리소스 정책)은 서로 다른 출처가 리소스를 공유하기 위해 존재합니다. 웹 클라이언트가 다른 출처의 리소스를 요청할 때는 HTTP 프로토콜 REST API를 활용하여 요청을 보냅니다. 이때, 클라이언트는 요청 헤더에 Origin이라는 필드에 요청을 보내는 출처를 담아 보냅니다.

서버는 해당 요청을 응답할 때 'Access-Control-Allow-Origin'이라는 필드에 '리소스에 접근이 허용된 출처'를 담아 전송합니다.

이후 서버에서 응답을 받은 브라우저는 Origin으로 보냈던 값과 Access-Control-Allow-Origin에 있던 값을 비교하여 해당 응답이 유효한지 판단합니다.

이 과정은 웹 서버가 아닌 '브라우저'가 담당한다.

이러한 Cors 정책은 React, Spring 등을 통해 구현하는 스펙이 아닌, 구현되어 있는 스펙입니다.
서버에서 CORS를 위반하는 정책을 허용했더라도 브라우저에서 분석할 때, 해당 정책이 CORS를 위반했다면 해당 응답을 버리게됩니다.

이러한 이유로 Postman을 통해 CORS를 위반한 API를 전송하더라도 브라우저를 거치지 않기 때문에 정상적인 응답이 돌아오는 것입니다.

CORS의 방식

  1. Preflight Request
    일반적으로 가장 많이 사용하는 방식으로 리소스 요청 시, 예비 요청과 본 요청으로 나누어 전송하는 방식입니다.

이때 브라우저가 전송하는 예비 요청을 Preflight Request라고 합니다. 예비 요청은 일반적으로 사용하는 Get, POST, PUT, DELETE가 아닌 OPTIONS라는 메서드가 활용됩니다.

브라우저는 먼저 예비 요청을 전송하여 CORS를 만족하는지 검사하고 CORS를 만족한다면 본 요청을 전송하여 리소스를 받아오게됩니다.

  1. Simple Request

회사에서 겪었던 문제를 해결할 수 있었던 방식입니다. fetch 메서드의 'no-cors'옵션을 사용하면 예비 요청없이 바로 본 쵸엉을 보내며, 본 요청에 대해 CORS 정책을 검사하는 방식입니다.

이는 다른 웹 사이트에 API를 사전적으로 전송하여 해당 사이트가 열려있는 사이트인지, 정책 혹은 닫혀있는 사이트인지 판별할 수 있었습니다.

하지만 Simple Request를 전송하기 위해서는 몇가지 규칙을 따라야 전송할 수 있습니다.

  • 요청의 메소드는 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만 허용됩니다.

일반적인 REST API의 경우 JSON 형태로 보내거나 인증을 위해 Authorization을 헤더에 포함하여 전송합니다. 하지만 Simple Request를 사용하기 위해서는 어떤것도 사용할 수 없기 때문에 일반적인 환경에서는 사용하기 어려운 방식입니다.

  1. Credential Request

다른 출처 사이의 통신에서 보안을 강화하고 싶을 때 사용하는 방식으로 헤더에 인증 정보를 담아 요청을 전송합니다.

  • 출처가 다른 경우에는 쿠키나 인증 관련 헤더를 보낼 수 없습니다. 보안상 중요하기 때문입니다. 이를 위해서는 백엔드와 프론트엔드 모두 CORS를 설정해야합니다.

사용 방법

  • fetah API에서는 credential 옵션을 사용하며 3가지 옵션 중 하나를 선택합니다.
  1. same-origin(기본값) : 같은 Origin 사이에만 인증 정보를 담는다.
  2. include : 모든 요청에 인증 정보를 담는다.
  3. omit : 모든 요청에 인증 정보를 담지 않는다.
  • Axios에서는 withCredentials를 사용하며 true, false로 선택할 수 있습니다.

이 때 서버는
1. 응답 헤더에 Access-Control-Allow-Credentials: true를 넣어 전송합니다.
2. 응답 헤더의 Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Ctonrol-Origin-Header에 * 와일드 카드를 설정하지 않아야합니다.

정리

외부 사이트의 접근을 위해 많은 부분을 학습했던것 같습니다. XMLRquest와 Fetch 메서드에도 GET, POST, PUT, DELETE 외에 다양한 옵션이 있고 정책을 만족하기 위해서 많은 방법이 있다는 것을 알 수 있었습니다. 프론트, 백의 지식만이 아닌 네트워크 지식도 지속적으로 공부를 해야할 것 같습니다

참조


CORS 개념 정리

CORS와 Credentials

profile
매일 발전하는 프론트엔드 개발자

0개의 댓글