본문 바로가기
트러블슈팅

Spring Security와 CORS 에러 대응

by wwns 2023. 1. 3.
반응형

이전 글에 이어서 CORS가 또 발생하였다. 이전에는 어찌어찌 해결했었지만, 프론트 쪽에 웹 도메인을 부여하고 나서 다시 발생하였다. 확실하게 HTTP 통신을 이해하고 있지 못했던 것 같다.

여기서 나오는 용어나 개념은 이전글을 참고하거나, 검색해보시길 바랍니다.!

 

1. 재 발생 이유

SpringSecurityConfig - FilterChain
corsConfig

스프링 시큐리티 FilterChain에 cors를 활성화하고, cors에 allow origin, method, header를 설정하였다. 이렇게 설정을 해놓으니, 프론트 팀 로컬에서 작업하던 localhost:3000에 대한 요청은 cors가 발생하지 않고 잘 해결되었었다.

 

그런데, Stage 서버에서 Swagger가 작동하지 않아 알아본 결과, Filter에서 AllowOrigin에 도메인을 적지 않았기 때문이었다.

// swagger문서가 배포되는 웹 도메인 추가함
configuration.setAllowedOriginPatterns(List.of("http://localhost:3000", "https://api.mydomain.com"));

이렇게 변경해주니 swagger에서도 잘 동작하였다.

 

잘 사용하다가 프론트 쪽 웹도 배포용 도메인을 구매한 후 서버에 올려 API호출을 했더니 다시 CORS에러가 발생되었음.

 

이번 CORS의 문제는 관리자모드를 켜고 확인해본 결과 Preflight Request가 403이 뜨면서 실제 요청까지 거부가 돼버리는 상황이었다. -> Preflight Request가 무엇인지는 이 글을 참조 하였음.

해결방법

  • 내가 한 cors config의 allowedMethods에 OPTIONS 메서드를 추가한다.
    • Preflight Request시 OPTIONS 메서드가 허용되지 않았었음.

가벼운 문제인 줄 알고 OPITONS만 추가해서 얼른 pr을 올렸었다. Preflight Test를 하는 방법을 몰랐음..

// OPTIONS 메소드 추가
configuration.setAllowedMehtods(List.of("OPTIONS", "...", ..));

하지만 여전히 Preflight Request는 통과하지 못하고 403을...

 

2. SpringSecurity에서 제공되는 CORS 필터 분석

CORS 필터가 어떤 구조이길래 통과가 안 되는 것인지 알아보도록 했다.

Spring Security에서 추가한 CORS Filter

  • corsConfigSource로부터 HttpServletRequest의 Configuration을 가져온다
  • CORS Processor로부터 Request에 대한 처리를 진행한다.

CORS Proccssor Request 처리 과정 - DefalutCorsProcessor.java

  • Origin과 Mehtod, Header를 체크하고 CORS 상황이 아니라면 true를 반환하며 이것이 isValid의 값이 된다.
  • 그 후, isValid와 isPreflightRequest를 검증하고 CORS 필터를 종료하게 된다.

마지막에서 문제가 발생한 것이다. 결국엔 CORS 필터는 CORS 상황이 일어나면 connection을 refuse 하기 위해 만들어진 것이다. 그런데, Preflight Request 자체는 이미 Cross Origin이라는 상황을 말하기 때문에 무조건 거절이 되도록 설정이 되어있었다.

우리는 프론트와 백엔드를 분리하여 개발을 진행하기 때문에 두 웹 서버 사이에서는 CORS가 발생하면 안 된다. 따라서 isPreflightRequest만 적절히 넘어갈 수 있도록 CustomFilter를 만들어 적용시키도록 하였다.

 

3. CustomFilter

  • CorsUtils.isPreFlightRequest를 통과할 수 있도록 200을 반환하게 해 주었다.

Filter Chain

  • Security에서 제공되는 필터의 위치를 보고 같은 위치에 둘 수 있도록 적용하였음. (CorsFilter는 제거하였음)

cors를 해제하고, CustomCorsFilter를 추가하였음

4. 테스트

  • local test는 성공

  • 허용되지 않은 ORIGIN에서는 실패

 

로컬과 실제 배포 상황과 다르다 보니 쉽게 테스트해보지 못하고 정말 힘들었다.. -> ChatGPT에 물어보니 테스트 방법을 알려줘서 위와 같이 테스트할 수 있었다 ㅎㅎ. 요즘 자주 애용합니다!

이젠 CORS는 안 나오길 바라며..

반응형