반응형

WebSecurityConfigurerAdapter를 통해서 설정파일을 구성하는데,

csrf옵션을 임의로 disable해주지 않으면, 기본적으로 enable 설정으로 들어가게 된다.


따라서, 모든 api들이 csrf token을 필요로 하게 되고, 이게 없이 요청이 온 client에게는 405 method allow 라는 오류를 리턴한다.


api허용을 하지 않겠다는 의미면, 405보다는 403이 되어야 하지 않나라는 의문이 들어서,

csrf token이 없거나 만료된 경우 403을 주도록 수정을 해보았고, swagger-ui를 통해 운영 관련한 API를 이용해야 하는데,

swagger를 뜯어서 csrf token을 넣어주지 않는 이상 이용할 수 없겠다 싶어서, 우회하는 방법까지 찾아보게 되었다.


일단 간단한, csrf token을 검사하지 않도록 우회하는 방법부터!


WebSecurityConfigurerAdapter를 상속받아서 클래스를 하나 만들게되면, configure메소드를 구현하라고 나온다.

아래와 같이 csrf 관련 옵션에 ignore시키는 구문을 추가해준다. 

admin/ 이후의 모든 api들이 csrf token검사 없이 사용가능하게 허용되었다!


@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().ignoringAntMatchers("/admin/**");
}



그 다음으로, 잘못된 csrf token인 경우에 대한 403처리.


csrf token이 잘못된 경우 log level을 debug로 변경해서 확인해보면,

InvalidCsrfTokenException이라는 Exception을 발생시키는 것을 확인해볼 수 있다.


보통 Exception Handling은 어떤 시점에서 해야되느냐가 가장 관건인데, 

Spring Security에서는 해당 Exception을 쉽게 Handling할 수 있도록 제공을 한다.


방금 수정했던 configure 메소드에 다음과 같은 부분을 추가해보도록 하자.


@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().ignoringAntMatchers("/admin/**").and()
        .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());
}



아마 CustomAccessDeniedHandler가 없다고 할텐데, 이건 해당 설정 값에서 원하는 interface를 받아서 직접 구현을 해주어야 한다. 


import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.csrf.InvalidCsrfTokenException;

public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {
        
        if(accessDeniedException instanceof InvalidCsrfTokenException) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        }
          // 추가 (서버가 재시작된 경우 csrfToken이 없어지게 되므로, 아래와 같은 Exception이 발생함
        if(accessDeniedException instanceof MissingCsrfTokenException) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        }
    }

}




이제 csrfToken이 잘못된 경우에도 403 오류를 받을 수 있도록 수정이 되었다.

반응형
,
반응형