CORS & SOP에 대해 알아보자 -2탄

1

공통

목록 보기
3/9
post-thumbnail
post-custom-banner

출처

CORS에 대한 복습 🛠️

지난 포스팅에서 Cross-Origin Resource Sharing(CORS)와 Same-Origin Policy(SOP)의 간단한 소개를 했는데요. 지난 포스트에 대해서 3줄 요약을 하자면,

  1. 일단 URL에는 Protocol+HOST+PORT (ex: https://www.naver.com:8000) 이 3개의 조합으로 자원의 출처를 구분한다
  2. 이 출처가 다르다면 Same-Origin Policy에 걸려서 브라우저에서 에러를 발생시킨다.
  3. 하지만, 웹이라는 환경에서 다른 출처의 이미지/링크/기타 등등 다른 자원을 사용못하는 것은 불가능하기 때문에 CORS 조약을 충족하는 자원에 대해서 공유를 할 수 있도록 한다

CORS의 3가지 시나리오 📖

위의 3줄요약고 더불어서, 이번에는 CORS가 허용되는 3가지 시나리오에 대해서 설명하는 포스팅을 해보겠습니다.


첫번째 시나리오 : Preflight Request ✈️

이 방식의 요청은 웹개발에서 가장 많이 마주치는 시나리오로써, 브라우저는 요청을 한번에 다 보내지 않고 예비요청과 본 요청을 나누어서 보내게됩니다. 여기서, 예비요청이 바로 영어로 Preflight Request인데, 이것을 하는 이유는 먼저 해당 서버에서 어떤 출처와 방식을 허용하는지 미리 확인하고, 그 다음 본 요청을 보낼려고 하기 때문이예요. 옛말에 돌다리도 두드려보고 건너라는 말처럼 말이죠. 한 번 확인하고 밑의 그림을 참고해주세요 !

위의 사진을 정리하자면,

  • 브라우저는 예비요청을 HTTP method 중 OPTIONS를 이용해서 다음과 같은 확인 사항을 검사한다.

    • Origin : 출처 정보 (서버에서 허락한 출처의 요청인지 검사)
    • Access-Control-Request-Method : HTTP METHOD가 유효한지 검사
    • Access-Control-Request-Headers : 본 요청에 HTTP의 HEADER가 유효한지 검사

  • 서버는 해당 예비요청에 대한 응답으로 허락된 정책에 대한 정보를 제공한다.

    • Access-Contorl-Allow-Origin : 서버가 허락한 출처들 (Protocol + Host + Port)
    • Access-Control-Allow-Methods : 허락한 HTTP Method 리스트 업
    • Access-Control-Allow-Headers : 허용되는 HEADERS 정보 (* 와일드 카드시 전부 허용하지만, Authorization은 따로 명시해야됨)
    • Access-Control-Max-Age : 서버가 preflight요청에 대한 응답의 수명 (초 단위)

  • 하지만, 여기서 중요한 것은 이 예비요청의 응답 성공여부와 상관없이 CORS에러가 발생할 수 있다는 점이다. 예를 들어, 가끔씩 Preflight Request가 200 성공 응답을 주었어도 브라우저에 CORS에러가 나와 많이 당황한다. 이렇게 되는 이유는 일단 CORS 에러가 발생하는 시점이 예비 요청을 받고난 직후이기 때문이다. preflight request에서 검사한 정보에서 더 추가된 정보가 있거나, 메인 요청의 URL이 달라졌기 때문에 메인 요청에서 CORS 에러가 발생할 수 있다.

  • 이 Preflight Request 방식은 밑에서 설명할 Simple Request 방식에 적용될 수 없을 때 사용됩니다. 즉, 밑의 Simple Request에 해당 사항이 없다면 예비요청이 발생 됩니다.

두번째 시나리오 : Simple Request 📦

두번째 시나리오는 바로 기본 요청(Simple Request)으로, 예비 요청을 보내지 않고, 바로 HTTP Request를 하는 방식입니다. 이 방식이 적용되는 경우는 밑의 조건들을 충족하는 상황입니다.

  1. 다음 중 하나의 메서드
  • GET
  • POST
  • HEAD
  1. 웹 브라우저가 자동으로 설정한 헤더들만을 포함
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • DPR
  • Downlink
  • Save-Data
  • Viewport-Width
  • Width 1번 조건 같은 경우 충족하기 그리 어려운 것은 아니지만, 문제는 2번 조건이다. 대부분의 http 통신에서 text/xmlapplication/json을 포함하는 경우가 대부분이기도 하고 복잡한 웹어플리케이션에서 추가적인 헤더를 사용하지 않을 수가 없기때문에 앞으로 프로젝트 진행하면서 볼 수 있을지 ... 흠 ... 😗

세번째 시나리오 : Credential Request 🔒

세번째 시나리오는 인증된 요청을 사용하는 방법입니다. 브라우저가 제공하는 리소스 요청인 XMLHttpRequest 객체나 fetch 는 기본적으로 인증과 관련된 쿠키나 헤더를 요청에 함부러 담지않고, credentials옵션을 적용해야지 담을 수 있습니다.

credential은 3가지 옵션을 가지며 다음과 같이 fectch를 사용할 때 옵션값을 설정하여 요청을 보낼수 있다.

  • Credentials 옵션
    1. same-origin (기본값) : 같은 출처간의 요청에만 인증 저보를 담을 수 있다.
    2. include : 모든 요청에 인증 정보를 담을 수 있다.
    3. omit : 모든 요청에 인증정보를 담을 수 없다.

예시 1)

fetch('내서버주소', {
 credentials: 'include', // 모든 요청에 인증 정보를 포함하겠다는 의미
});

예시 2)

fetch('내서버주소', {
 credentials: 'omit', // 모든 요청에 인증 정보를 담을 수 없다는 의미
});

해당 credentials 옵션을 include로 설정했을 때, CORS 정책에 2가지 항목이 더 추가된다


  1. Access-Control-Allow-Origin에는 *를 사용할 수 없으며, 명시적인 URL이어야한다.
  2. 응답 헤더에는 반드시 Access-Control-Allow-Credentials: true가 존재해야한다.

이 시나리오가 더 까다롭게 다가올 수 있지만, 보완과 인증에 관련된 정보를 요청에 포함하고 있기 때문에 더 빡빡한 검사 조건을 포함하는 것은 당연하다고 생각한다.

Cors 에러 발생시 접근 방법💡

나는 아직 웹개발을 본격적으로 시작한 것은 아니지만, 일단 모든 에러는 해당 원인이 무엇에서 비롯되었는지 파악할 수 있어야 시간을 더 단축할 수 있다고 생각한다.

위의 CORS 에러같은 경우 에러는 브라우저에서 발생하지만, 생각해보면 모든 것은 서버의 설정을 바꿔줘야지 해결되는 것들 이기 때문에 (예를 들어서, 허락한 출처 기입 + 헤더) 백엔드가 해결해야되는 문제라고 생각한다. 예를 들어, 아무리 프론트가 Request를 뜯어 고쳐도, 그 Reqeust가 오는 출처를 웹서버에서 허락하지 않는다면 어떤 방법도 안 통하기 때문이다.

추가적으로 해당 CORS 정책이 어떻게 적용되는지 전체적인 그림을 파악해야 나중에 문제해결에 용이할것이며, 프론트 팀원들과의 불화도 줄일 수 있을것이라고 생각한다.

-끝!-

profile
# 개발 # 컴퓨터공학
post-custom-banner

1개의 댓글

comment-user-thumbnail
2021년 2월 28일

"모든 에러는 해당 원인이 무엇에서 비롯되었는지 파악할 수 있어야 시간을 더 단축할 수 있다고 생각한다"
동의합니다!!!!!

답글 달기