CORS 에러, 공부해보자!

Polla·2023년 8월 9일
1

개인정리

목록 보기
1/4
post-thumbnail

프로젝트 내내 시달렸던 CORS 에러, 대체 무엇일까?


PalmSpring을 하면서 가장 힘들었던 순간이 언제냐고 물어보면
나는 CORS 에러가 터지는 매 순간이라고 대답하고 싶다. 

그만큼 정말 공부하고 싶었고, 일주일의 쉬는 기간이 주어진 김에 시작하는 CORS 에러 정복

CORS,
웹 개발을 처음 해보신 분들은 무조건 거쳐가는 관문이다. 물론 나도

나는 CORS를 약 6월달 해커톤에서 처음으로 마주했고,
이후 PalmSpring이라는 큰 프로젝트에서 다시 한번 마주하게 되었다.

그 당시에도 생전 처음보는 코드에 꽤나 당황해서 여기저기 도움을 요청했던 기억이 난다...🥹

1. CORS 왜 발생하는가?


CORS를 이해하기 위해서는 발생의 기원부터 들어가보려고 한다.
CORS 라는 것은 SOP라는 정책을 어기는 경우 발생하게 된다. 이 SOP란 무엇일까?


1-2. SOP?


이는 Same-Origin-Policy
라는 뜻으로 2011년에 RFC 6454 에 등장하게 된 보안 정책 방식입니다.

여기서 RFC란? RFC에 대해 궁금하실까봐.. 사실 내가 궁금해서 찾아봄

Request-For-Comments 라는 뜻으로 국제 인터넷 표준화 기구에서 관리하는 기술 표준으로
승인되는 경우 RFC 뒤에 일련의 번호가 붙은채로 불리게 됩니다.

CORS는 다만 이 정책이 나오기 전에 등장했다고 합니다 신기하죠잉

말을 인용하자면

known colloquially as the "same-origin policy". Although this
security model evolved largely organically, the same-origin policy
can be understood in terms of a handful of key concepts. This
section presents those concepts and provides advice about how to use
these concepts securely.

3.1. Trust

The same-origin policy specifies trust by URI. For example, HTML
documents designate which script to run with a URI:

SOP 즉, 동일 출처 정책은
URI를 기준으로 신뢰성을 파악하고 있다고 나와있습니다.


1-1. CORS?


그렇다면 위를 어겼을때 나오는 CORS란 무엇일까요?

Cross Origin Resource Sharing 의 줄임말입니다.
단어 그대로, 서로 다른 Origin 간의 자원 교환이 일어나는 것을 의미하는데

예시를 하나 들어서


백엔드는 8080 PORT 를 기본으로 하는 Spring Boot로 개발하고
프론트에서는 3000 PORT 를 기본으로 하는 React로 개발했다고 가정해보았을때

이때 이 Origin의 접근이 허가받지 않은 접근 즉,
Access-Control-Allow-Origin에 들어가 있지 않은 Origin일 경우 CORS Error가 발생하게 됩니다.

간단한 예시는 이렇고 실제는 Port 보다는 좀 더 복잡한데
여기서 Origin과 URI에 대해서 알아보고자 합니다.



2. Origin? URI?



여기서 Origin이란, 특정 페이지에 접근할 때 사용되는 Url의
Scheme(프로토콜), Host(도메인), Port(포트) 을 말하는데

여기서, Same-Origin 이란 이 3가지가 일치할 때 이고
3가지 중 하나라도 다르면 Cross-Origin 이라고 불리게 됩니다.



3. CORS의 동작방식



개발자들이 CORS 에러를 마주하고 해결방식을 찾아보면,
방법들이 정말 많이 나오는데 그 방법이 다 가지각색이라 정말 당황스러웠습니다.🤧
제가 그랬습니다.

이유는 CORS 자체가

  • Simple Request
  • Preflight Request
  • Credentialed Request

이 3가지의 동작방식이 있기 때문인데,

3-1. Simple Request


첫번째 Simple Request의 동작방식일 때는 몇가지 조건 사항이 있습니다.

  • 요청 메서드(method)가 GET, HEAD, POST 중 하나
  • 사용 가능한 Header는
    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 중 하나만 가능

이때는 다른 것들은 하지 않고, 단순히 아래와 같은 코드를 작성해
위에서 설명한 Origin 만 비교한 채 접근을 허용하게 됩니다.

Access-Control-Allow-Origin : https://foo.example

다만, 보통은 Content-Type을 application/json 으로 보내는 경우가 다수 이기 때문에
이때는 위와 같은 방식이 아닌 Preflight Request로 동작하게 되는데요.


3-2. Preflight Request


이때는 Pre, 미리 flight 날린다.
라는 이름에 걸맞게 브라우저가 본 요청을 바로 보내는 것이 아닌, 안전한지 검증하기 위한
예비 요청 Preflight Request를 먼저 보내

이때 브라우저가 Options 메서드를 사용하여 Header에
실제 요청에 사용할 Method와 Headers를 담아서 보내게 됩니다.

이후 서버에서

  "Access-Control-Allow-Origin", "https://test.palmsummer.site"
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Allow-Methods","*");
            httpResponse.setHeader("Access-Control-Max-Age", "3600");
            httpResponse.setHeader("Access-Control-Allow-Headers",

이와 같이 허용을 해주는데
이는 F12를 통해 응답 헤더에서 확인할 수도 있습니다.



3-3. Credentialed Request


3번째로 Credentialed Request는

쿠키와 토큰 같이 자격인증 정보 즉, Credentials를 같이 전송할때 발생하게 됩니다.

이때는 서버에서 헤더에
Access-Control-Allow-Credentials 를 true로 설정해주고 보내줘야 하는데
다만 인증정보를 보낸 다는 점에서 기존에서 사용하던

와일드 카드 (*)의 사용을 브라우저가 막게 됩니다.
이 점 때문에 꽤나 삽질했습니다.^^...

  "Access-Control-Allow-Origin", "https://test.site"
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Allow-Methods","POST, GET, DELETE, PUT");
            httpResponse.setHeader("Access-Control-Max-Age", "3600");
            httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization" )

예를들어 이와 같이
정확히 명시해서 보내줘야 한다는 겁니다.


4. 마무...리?



자 이제 다 끝났니? 이제 개발을 하자

CORS 에러를 우리 팀은 Filter을 이용하여 구현했었다.
정말 여기 나와있는 모든 방법을 다 해봤던것 같다 눈물 좔좔

다만, 다들 알겠지만 굳이 Filter가 아니더라도 CORS를 상대할 수 있는 방법은 많다는 사실!

각자의 서비스에 어울리는 방법을 생각하고 고민해보는 개발이 되었으면 좋겠다.
물론 나도....

그럼 여기까지!

profile
트러블 슈팅 Blog => https://polla.palms.blog/home

2개의 댓글

comment-user-thumbnail
2023년 8월 9일

좋은 글 감사합니다. 자주 올게요 :)

1개의 답글