Spring Security, ExceptionHandling 중 원하지 않는 Status 가 나올 때

조원준·2022년 8월 12일
0

배경

스프링 시큐리티에 authenticationEntryPoint 를 사용하여 ExceptionHandling 을 할 때 원하지 않는 응답으로 나오는 이슈가 있었다.

원하지 않는 응답이란, 앞 단에 JwtToken 을 검사하고 인증정보를 SecurityContextHolder 에 넣어주는 로직을 넣어두었는데 해당 필터를 거치기도 전에 AuthenticationErrorHandler 로 빠져버리며 '401' 스테이터스를 출력하였다.

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final AuthenticationErrorHandler authenticationErrorHandler;
  
    public WebSecurityConfig(AuthenticationErrorHandler authenticationErrorHandler) {
        this.authenticationErrorHandler = authenticationErrorHandler;
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
      httpSecurity
          .csrf().disable()
          .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
          .exceptionHandling()
              .authenticationEntryPoint(authenticationErrorHandler);
    }
}
@Component
public class AuthenticationErrorHandler implements AuthenticationEntryPoint {

	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
	}
}

문제점

결론부터 얘기하자면 전송하는 API URL 에 슬레시(/) 가 두번 연속 들어가 더블 슬레시(//)로 들어갔기 때문이였다.

이제부터 이 전송이 스프링 시큐리티 내부적으로 어떻게 처리되는지, ErrorHandler 로 빠지지 않게 할 수 있는 방법이 무엇인지 알아보자

왜 문제가 발생되었나?

스프링 시큐리티는 프록시 패턴으로 된 필터에서 필터를 돌리기 전 기본적인 방화벽(Firewalled) 검사를 진행한다.

FilterChainProxy.java

해당 firewall 에 대한 Bean 설정이 따로 안되어 있다면 StrictHttpFirewall.java 를 기본설정으로 두고 요청/응답에 대한 검사를 한다.

몇가지 기초 블랙리스트 설정을 거치고 해당된다면 RequestRejectedException 을 발행한다.

StrictHttpFirewall.java

문제는 해당 블랙리스트 기초 설정에 더블 슬레시(//)가 포함되어 있어 RequestRejectedException 가 발행되므로 나비효과가 시작되었다.

왜 RequestRejectedException 발행이 문제인가?

StandardWrapperValve.java

  • 요청부에 발생된 exception 클래스를 set 해주는 모습
  • TODO / 보완예정
  • RequestRejectedException 이 AccessDeniedException 클래스로 변환되는 시점
  • SecurityContextHolder 에 AnonymousAuthenticationToken 으로 초기화 되는 시점

ExceptionTranslationFilter.java

요청부가 RequestRejectedException 이 떨어지면 응답부에 출력을 줄 때 AccessDeniedException 이 발생되고 요청부에서 이미 SecurityContextHolder 에 대한 Clear 가 된 시점에서 결국 AnonymousAuthenticationToken 으로 초기화 되었기 때문에 AuthenticationErrorHandler 에 InsufficientAuthenticationException 이 발생되면서 '401' 스테이터스가 출력되었다.

profile
뿌리를 생각하는 나무 개발자

0개의 댓글