CORS의 기본 개념과 동작 방식(부제: Preflight 요청이란?)

Jiwon Joung·2022년 11월 23일
12

Web

목록 보기
1/2

CORS란?

우선 Preflight request를 이해하기 위해선 CORS에 대해서 알아야한다. CORS란 Cross-Origin Resource Sharing 의 줄임말로, 직역하면 교차 출처 리소스 공유라는 뜻이다.

CORS는 “다른 출처”에 리소스를 요청할 때 지켜야하는 정책이다. 여기서 “출처 (Origin)”라 함은, url에서 Protocol, Host, Port 까지를 의미한다.

Cross-Domain 환경에서는 CORS(Cross-origin resource sharing / 교차 출처 리소스 공유) 정책으로 인증이나 쿠키같은 민감한 정보의 교환이 까다롭다.

쉽게 말하면, API를 요청하는 프론트와 요청을 받는 백엔드의 url이 다르면 CORS policy에 위반해서 아래와 같은 느낌의 에러를 뱉게 된다… (보니까 PTSD 돋네요)

CORS가 발생하는 예시는 다음과 같은 상황이다.

  • 백엔드는 EC2로 배포해놓고 프론트는 로컬에서 작업하는 경우
  • 백엔드와 프론트를 다른 url로 배포하는 경우

위의 에러는 웹개발을 하다보면 정말 자주 마주하는 에러기때문에 종종 사람들이 CORS 자체가 에러의 유형이라고 생각하기도 하는데, 정확히 말하면 CORS 자체는 “브라우저 정책”이고, 이 정책에 위반하면 has been blocked 에러가 나는것이다. 웹개발을 하다보면 이 에러를 만났을 때 엄청엄청 열받는데, 사실 CORS는 오히려 불가능한 다른 출처간 요청을 가능하게 도와주는 정책이라고 할 수 있다.

해결방법

이 포스팅에서는 CORS해결법을 다루는건 아니니 간단하게 결론만 얘기하자면, 사실상 프론트쪽에서 처리할 수 있는 방법은 없습니다.

백엔드는 아예 몰라서 정확한 방법을 기술할 수는 없지만, API 배포시에 Access-Control-Allow-Origin 을 와일드카드(*)로 열거나 프론트쪽 url을 추가해주는 방식으로 해결할 수 있다.

이게 왜 필요할까?

CORS 정책이 없이 자유롭게 다른 Origin으로 요청을 보낼 수 있다고 생각해보자. 악의적으로 정보를 빼내는 코드를 담은 요청을 API에 보내서 로그인 정보를 가져온다던지, 무한요청을 보내서 웹서버를 터뜨리는 일도 가능할 것이다. 이런 좋지않은 상황을 방지하기 위해 “허용되지않은 출처”에서 보내는 요청을 브라우저단에서 막는 것이라고 생각하면 된다.

CORS의 동작원리

CORS가 뭔지 알아봤으니, CORS의 동작원리를 한번 알아보자

동작원리는 크게 세가지가 있다.

  • 단순 요청을 보내는것 (Simple Request)
  • 예비 요청을 보내서 확인하는것 (✈️ Preflight)
  • 인증된 요청을 사용하는 방식 (🔐 Credential Request)

Simple Request

말그대로 단순히 요청을 보내는 방법인데, ❗특정 조건하❗에서 그냥 요청을 보내봐도(?) 되겠다고 판단해서 예비요청 없이 서버에 바로 요청을 보내는 방법이다.

서버에 바로 본요청을 보낸 뒤, 서버는 헤더에 Access-Control-Allow-Origin 값 등등을 붙혀서 보내주면 브라우저가 CORS 정책 위반 여부를 검사한다.

조건

  • GET, HEAD 요청
  • Content-Type 헤더가 다음과 같은 POST 요청
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안된다.

⇒ 사진 파일 업로드(multipart/form-data)가 아니라면 대~~체로는 REST API가 Content-Type 으로 application/json 을 사용하기 때문에 사실상 지켜지기 어려운 조건이고, 거의 대부분은 Preflight 방식으로 처리한다.

✈️ Preflight Request

서버로 바로 요청을 보내는 Simple Request와는 다르게, 지금 보내는 요청이 유효한지를 확인하기 위해 OPTIONS 메서드로 예비 요청을 보내는 것이다.

이게 왜 필요하냐면… 만약에 크기 10000짜리 Array를 body에 담아서 보내는 요청이 있다고 해보자. 근데 만약 이 요청이 CORS 정책을 위반하는 요청이라면 ?! 이거를 그냥 무작정 보내버렸는데, 알고보니 유효하지 않은 요청이라면 굉장히 불필요하게 리소스를 낭비한 꼴이되고, 서버에도 부하가 크다.

이를 방지하기 위해서 특정 조건인 경우 예비요청을 먼저 날려, 이게 유효한 요청인지 확인하는 것이다.

조건

  • Content-Type이 다음과 같은 GET, HEAD, POST 요청
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • 요청에 사용된 XMLHttpRequest.upload 객체에 이벤트 리스너가 등록되어 있지 않을 때
  • ReadableStream 객체가 요청에서 사용되지 않을 때


위의 캡쳐는 내가 실제로 개발중에 preflight를 날린걸 포착(?)한 예시인데, 실제로는 levels에 대한 api 호출은 한번만 했는데, preflight까지 총 두번 날아간것을 확인할 수 있고, 이게 CORS에 위반해서 본 요청도 자동으로 거절된 것을 확인할 수 있다.

Credendential Request

Credential Request 는 인증된 사용 요청 방식인데 .. 이것은 나중에 따로 문서를 두고 다루도록 하겠다.

0개의 댓글