❗ 문제
스프링 부트와 리액트로 개발하는 과정에서 axios POST로 multipart 전송을 했더니 발생한 오류다. GET으로 할 때는 문제가 없던 터라 오타가 났다거나 파일이 보내는 과정이 잘못되었다고 생각해서 엉뚱한 곳을 찾아보고 있었다. 더욱이 스프링 시큐리티는 처음이라 이 오류가 CORS에서 걸린 줄도 몰랐다. 스프링 시큐리티, CORS, CSRF 관련해서 공부할 수 있었던 좋은 기회라고 생각했다.
💡 해결
http.csrf().disable();
멀리 돌아와서 그렇지 해결방법은 생각보다 간단했다. 이 방법을 초반 서치할 때 보았음에도 적용할 수 없었던 이유는 SpringSecurity 설정 파일을 못 찾았던 이유였다.(+ 스터디로 시작한 프로젝트라서 설정을 내가 하지 않았다..) Application.java와 SecurityConfiguration.java 파일이 다른 패키지에 있었는데 나는 Application.java의 corsConfigurer 메서드를 보고 여기가 문제 지점일 거라 생각했다. 해당 메서드를 빈으로 가지고 있었고 CorsRegistry를 관리하는 메서드를 반환했다. 하지만 allowedMethods는 default였고 default는. GET, HEAD, POST를 가진다고 했다. 그렇다면 이 부분은 문제가 없다는 소리였다.
이 외에도 리액트 package.json에서 http://localhost:8080를 적용하거나, Controller에서 @CrossOrigin(origins = "http://localhost:3000")을 추가, setupProxy 파일로 별도 생성 그리고 webpack-dev-server로 리버스 프록싱은 하다가 도저히 아닌 것 같아 멈추고 백엔드를 다시 살펴봤다. 돌고 돌아서 다시 config 파일들을 다시 살펴보니 SecurityConfiguration.java 안에 HttpSecurity라는 익숙한 클래스를 찾았고, filterChain() 메서드에서 사용하고 있었다. filter는 DispatcherServlet 앞에 위치해있다. 요청과 controller 사이에 filter가 있다고 보면 된다. 문제 지점은 여기였고, http.csrf().disable(); 코드를 추가하니 200번 정상 코드를 보냈다.
추가적으로 CSRF를 무력화시켜도 될까?라는 의문이 들어서 찾아봤다.
보통 타임리프와 jsp 같은 템플릿엔진을 사용할 경우 CSRF Token을 자동 생성할 수 있다. 하지만 React의 경우 템플릿 엔진이 배제되었기 때문에 1. 토큰을 컴포넌트화하는 코드 작성 2. CSRF 검증을 하지 않는 방법을 사용해야 한다.
상용되는 서비스라면 전자의 방법을, 리액트 스터디의 목적을 가진다면 후자의 방법을 택하는 것이 좋겠다.
CORS ( Cross-Origin Resource Sharing )
교차 출처 리소스 공유, 출처가 다른 리소스 간의 공유를 말한다.
CSRF ( Cross-Site Request Forgery )
사이트 간 요청 위조, 사용자의 의지와 무관하게 공격자가 의도한 행위를 특정 웹사이트에 요청하게 하는 공격
Spring Security
Spring 기반의 애플리케이션의 보안을 담당하는 스프링 하위 프레임워크
인증과 권한에 대한 부분을 Filter흐름에 따라 처리한다.
Filter는 Dispatcher Servlet으로 가기 전에 적용됨, 가장 먼저 URL요청을 받음
Interceptor는 Dispatcher와 Controller 사이에 적용됨
[ 참고 ]
- https://evan-moon.github.io/2020/05/21/about-cors/
- https://mangkyu.tistory.com/76
- https://icthuman.tistory.com/entry/Spring-Security-%EA%B8%B0%EB%8A%A5-%ED%99%9C%EC%9A%A9-1-Filter-Chain
- https://dev-pengun.tistory.com/entry/Spring-Boot-CORS-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0
- https://iseunghan.tistory.com/302