Swagger 로 Spring Security 적용 후 REST API 테스트하던 중 갑자기 403 에러가 식별됐다..

뭐가 문제일까 알아보니.. 스프링시큐리티를 적용하면 기본적으로 보안문제로 인해

CSRF 토큰이 없으면 403에러를 일으킨다고 한다..

기존 코드부터 살펴보자

public SecurityFilterChain exceptionSecurityFilterChain(HttpSecurity http) throws Exception {
        http

                .sessionManagement((sessionManagement) ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )

                .authorizeRequests((authorizeRequests) ->
                authorizeRequests
                        .requestMatchers("/api-docs","/api-docs/json/**", "/swagger-resources/**",
                                "/swagger-ui/**", "webjars/**","/swagger/**","/sign-api/**").permitAll()

                        .requestMatchers(HttpMethod.GET,"/product/**").permitAll()
                        .anyRequest().hasRole("ADMIN")
                        .and()

                        .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class)
                );

        return http.build();
    }
 

위의 코드를 보면 CSRF 관련 설정값이 없다.

추가해주자.

public SecurityFilterChain exceptionSecurityFilterChain(HttpSecurity http) throws Exception {
        http

                .sessionManagement((sessionManagement) ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )

                .authorizeRequests((authorizeRequests) ->
                authorizeRequests
                        .requestMatchers("/api-docs","/api-docs/json/**", "/swagger-resources/**",
                                "/swagger-ui/**", "webjars/**","/swagger/**","/sign-api/**").permitAll()

                        .requestMatchers(HttpMethod.GET,"/product/**").permitAll()
                        .anyRequest().hasRole("ADMIN")
                        .and()

                        .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class)
                )
                 // 추가한 부분
                .csrf((csrf) -> csrf.requireCsrfProtectionMatcher(new CsrfRequireMatcher()))
                .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
        return http.build();
    }
// 추가한 클래스(swagger일때 토큰 무시)
 static class CsrfRequireMatcher implements RequestMatcher {
        private static final Pattern ALLOWED_METHODS = Pattern.compile("^(GET|HEAD|POST|TRACE|OPTIONS)$");

        @Override
        public boolean matches(HttpServletRequest request) {
            if (ALLOWED_METHODS.matcher(request.getMethod()).matches())
                return false;

            final String referer = request.getHeader("Referer");
            if (referer != null && referer.contains("/swagger-ui")) {
                return false;
            }
            return true;
        }
    }

위 코드를 보면 CsrfRequireMather를 만든 이유는 swagger 환경에서 테스트할때는 CSRF 토큰 여부를 체크하지 않기 위해
적용한 것이다.

이제 정상적으로 동작한다.

만약 CSRF 를 전혀 사용하지 않는 환경이라면 위의 코드를 수정하여야 한다.

기존

 .csrf((csrf) -> csrf.requireCsrfProtectionMatcher(new CsrfRequireMatcher()))
 .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));

변경

 .csrf((csrf) -> csrf.disable());
 

+ Recent posts