Front - Back 서버를 분리하면서 만난 CORS 정책

CORS 정책과 SOP 이해를 통해 Front-Back 서버 통신 문제를 해결하는 과정과 경험을 공유합니다.
ImRieul's avatar
May 16, 2022
Front - Back 서버를 분리하면서 만난 CORS 정책
No 'Access-Control-Allow-Origin' header is present on the requested resource
 

CORS와 Origin 이해하기

CORS란 Cross-Origin Resource Sharing입니다. 대강 읽자면 교차하는 origin의 자원 공유라고 할 수 있습니다.
origin은 그저 github을 쓰면서 git remote add origin ...에서 본 기억밖에 없었습니다.
웹에서 origin은 schema + hostname + port를 뜻합니다. http request의 출처를 알리기 위한 것 같습니다.

Origin 확인하기

간단하게 F12를 눌러 개발자도구에서 콘솔 창에
window.location.hostname // reeul.tistory.com window.location.port // '' window.location.protocol // 'https:'
입력해보면 이렇게 나옵니다.
port가 비어있는 이유는 https의 기본 포트를 사용하고 있기 때문입니다(http - 80, https - 443).
간단하게 window.location.origin 하면 셋을 합쳐서 출력해줍니다.
 

SOP와 CORS 정책

CORS 정책을 설명하기 위해서는 SOP(same origin policy)라는 보안 정책을 알아야 합니다. 한 마디로 표현하자면 같은 출처(origin)에서만 요청, 응답을 해야 한다는 정책입니다. 브라우저가 접속하고 있는 origin과 서버의 origin이 일치해야 주고받을 수 있습니다.
이게 그렇게 중요할까 싶었는데 다른 출처에서 요청, 응답이 가능하다면 악성 코드가 있는 사이트에서 naver나 google에 로그인 유지 쿠키를 통해 해당 사이트에 요청을 보내고 응답까지 받아 빼돌릴 수 있게 됩니다. 악성 사이트에 접속하는 것만으로 내 주소록이나 메일이 빼돌려집니다.
좋은 정책이긴 하지만 front - back을 나누고 싶은 제 입장에선 여간 성가신 게 아니었습니다.
하도 삽질하다 우선 서버에 올리자는 심정으로 spring boot만 docker를 통해 aws서버에 안착시켰습니다. 하지만 제가 원하는 건 spring을 통해 react를 실행시키는 건 아니었습니다.
 

CORS 정책의 핵심

그럼 CORS 정책은 무엇일까요? 무려 다른 origin(출처)끼리 자원을 주고받을 수 있게 정해둔 정책입니다. 브라우저는 SOP과 CORS 정책을 준수하고 있습니다. 기본적으로 SOP 정책에 따라 브라우저의 origin과 response의 origin이 일치해야 하지만, access-origin-allow-header에 특정 origin을 명시해둔다면 브라우저의 origin과 response의 access-origin-allow-header 가 일치해도 자원(데이터)을 주고받을 수 있습니다.
제가 만난 경고는 CORS 정책을 이용하라는 뜻이었습니다..!

하도 삽질하다 우선 서버에 올리자는 심정으로 spring boot만 docker를 통해 aws서버에 안착시켰다. 하지만 내가 원하는 건 spring을 통해 react를 실행시키는 건 아니었다.
 

CORS 문제 해결 과정

처음엔 spring boot + react를 세팅하는 어느 블로그를 그대로 따라 하면서 만나보지 못한 에러였습니다. localhost:3000 <-> localhost:8080 끼리 http로 쉽게 통신하는 게 당연한 줄 알았고, 다른 서버에 http 요청, 응답에 대해 자세히 생각해보지 않았습니다. 문제는 aws서버에 올리고 난 이후였습니다. 제가 해결하기 위해 했던 일은 다음과 같습니다.
 
1. docker container 간 통신이 안 되는가?
깊게 생각을 안 하고 front container와 back container끼리의 문제인 줄 알고 docker에 대해 열심히 검색하며 volume까지 만들고 설정해주었습니다. container를 실행시킬 때마다 -v 옵션을 넣고, container끼리 ping이 잘 보내져도 에러는 마찬가지였습니다. 프론트엔드 서버와 백엔드 서버가 통신하는 게 아니라 클라이언트와 백엔드 서버가 통신하면서 생긴 문제였기 때문에 해결이 안 됐습니다.
 
2. CORS가 무엇일까?
우선 문제를 파악하기로 했습니다. 위에 써놓은대로 알고 난 뒤엔 CORS 정책대로 http 해더에 access-origin-allow-header에 프론트 서버 origin을 추가하기로 했습니다. 조금씩 바꿔가며 삽질해보니 몇 가지 알게 됐습니다.
  1. Spring boot 프로젝트를 처음 만들면 @SpringBootApplication이 붙은 클래스가 만들어지는데, 이 클래스는 spring의 설정 인터페이스 WebMvcConfigurer를 구현하고 있습니다.
  1. ip와 도메인을 같은 origin으로 인식하지 않습니다
 

결론

CORS 보안 정책을 통해 웹 서버 통신에 대해 다시 한번 생각해볼 수 있었고, 스프링 부트 구조도 익힐 수 있었습니다. http나 스프링 구조에 대해 더 공부해보고 프로젝트를 발전시켜야겠습니다.
Share article

Rieul's Index