이 벨로그는 CORS 개념 이해에 큰 도움을 받은 evan선생님의 깃허브 블로그를 참고해서 작성하였습니다. 이해하는데 굉장히 많은 도움이 됩니다.
지난 일요일에 WIL로 CORS에 관한 내용을 짤막하게 적었었다. 하지만 그 때 찾아보고 읽었던 글들은 이해하기가 어려웠었다. 오늘 성민짜짜와 CORS의 개념을 다시 한 번 짚어서 이해하고 문제가 발생하였을 때 어떻게 해결해야 하는지 알아보았다.
🚨 Access to fetch at ‘https://shoumini.shop/auth/signin’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
CORS, Cross-Origin Resource Sharing 정책은 교차 출처 리소스 공유라는 뜻으로 즉, 다른 출처간의 리소스(데이터) 공유에 관한 정책이다.
다른 출처? 교차 출처? 그렇다면 여기서 이야기하는 출처란 무엇인가?
예를 들어 내 벨로그 URL을 살펴보면 🔹https:// 는 Protocol, 🔹velog.io 는 host, 🔹@younseo1016 은 Path를 의미한다. 이외에 QueryString 이나 Fragment등이 올 수 있다.
이 때 출처 Origin은 protocol과 host, 위에는 나와있지 않지만 :80, :3030과 같은 포트번호까지 모두 합친 것을 의미한다. 서버를 찾아가기 위한 가장 기본적인 것들을 합쳐놓은 것이다.
위의 URL에 포트번호가 없는 이유는 생략이 가능해서인데, HTTP, HTTPS 프로토콜은 기본 포트가 정해져 있다.
포트번호의 의미와 역할 등을 추후 공부해 볼 예정이다.
웹에는 교차출처로의 리소스 요청을 제한하는데에 두 가지 정책이 존재한다. 그 중 하나가 CORS이고 나머지 하나는 SOP이다. SOP는 "같은 출처에서만 리소스를 공유할 수 있다" 라는 규칙을 가진 정책인데, 다른 출처에서 리소스를 가져와 사용하는 것은 너무나도 흔한 일이라 몇 가지 예외조항들을 두고 이 조항에 부합하는 리소스 요청만 출처가 달라고 허용하기로 하였다. 여기서 몇 가지 예외조항중 하나가 "CORS 정책을 지킨 리소스 요청"인 것이다!
내가 만약 다른 출처로 resource를 요청하면, 우선 SOP를 위반한 것이고 거기에 SOP 예외조항인 CORS 정책을 지키지 않는다면 아예 다른 출처의 resource를 사용할 수 없는 것이다.
그렇다면, 같은 출처와 다른 출처를 나누는 기준은 어떻게 될까?
URL의 Scheme, Host, Port 이 3가지가 동일하면 같은 포트, 다르면 다른포트이다. 예를 들어 https://velog.io/@younseo1016 에서 Scheme의 https://, host의 velog.io, 생략된 포트번호 :80 이렇게만 동일하다면 나머지는 모두 다르더라도 같은 출처로 인정이 된다.
user/frontend가 CORS 정책을 위반하는 리소스 요청을 하더라도 해당 서버가 같은 출처에서 보낸 요청만 받겠다는 로직을 가지고 있는 경우가 아니라면 서버는 정상적으로 응답을 하고, 이후 브라우저가 이 응답을 분석해서 CORS 정책 위반이라고 판단되면 그 응답을 사용하지 않고 그냥 버리는 순서이다.
CORS 정책을 위반하는 리소스 요청 때문에 에러가 발생했다고 해도 서버 쪽 로그에는 정상적으로 응답을 했다는 로그만 남기 때문에, CORS가 돌아가는 방식을 정확히 모르면 아주 골머리를 앓게 되는 것이다!!! 😐
🌟🌟 Access-Control-Allow-Origin 세팅하기 🌟🌟
서버에서 Access-Control-Allow-Origin 헤더에 알맞은 값을 설정해주면 된다.
예를 들어, Access-Control-Allow-Origin: https://velog.io/@younseo1016 이렇게 명시해주면, 이 출처에서 오는 요청은 받아주겠다는 것이다.
와일드카드인 *를 사용하면 모든 출처에서 오는 요청을 받아주겠다라는 뜻이 된다. 지금 당장은 편해도 정체를 모르는 이상한 출처가 데이터를 요청해도 받아갈 수 있으니 보안적으로 심각한 이슈가 발생할 수 있다.
내일 프론트랑 연결해서 CORS를 마주해보고 해결해봐야겠다!
(2022.10.26) 오늘 프론트랑 같이 연결해보는 과정에서 예비 요청을 콘솔창에서 직접 확인했다!!!!!! 신기했다. 아직 프론트의 기능구현이 다 된 상태가 아니라서 access를 와일드카드를 사용해서 모두 열어주었는데, 내일 기능 구현완료된 이후에 다시 프론트 주소값 넣어서 CORS를 해결해보려고 한다.
//우리 조의 1차 CORS 설정(모든 출처로부터의 요청을 허용함)
@Bean
public CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOriginPatterns(Arrays.asList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("POST","GET","DELETE","PUT"));
corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addExposedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}