Backend/SpringBoot

[Spring Security] CSRF 토큰 사용

Dean83 2025. 12. 16. 15:46

만일 쿠키 기반 SessionID 를 이용하여 인증할 경우에는 CSRF 토큰 사용을 하여 보안을 강화해야 한다. 그러나 만일 JWT를 이용하여 header 에 클라이언트가 수동으로 추가 할 경우에는 CSRF 토큰을 사용하지 않아도 되므로 이 페이지는 무시해도 된다.

 

보안에 관련된 내용은 여기에 있다. (https://dean83.tistory.com/380)

이 중  CSRF 토큰 발급을 통해 방어(?) 를 하는 내용에 대해 정리한다.  토큰 발급은 Springboot 에서 최초 요청시 토큰이 없다면 자동 발급 및 저장을 해 둔다. 단, 쿠키를 사용하지 않는 경우에는 별도의 url을 만들어 줘야 하고, 프론트에서 이를 요청해서 가져가야 한다.

@GetMapping("/csrf")
public CsrfToken csrf(CsrfToken token) {
    return token;
}

 

 

SecurityConfig 에서 CookieCsrfTokenRepository 사용 예

  • csrf 저장 repository를 CookieCsrfTokenRepository로 변경해야 하고, withHttpOnlyFalse를 통해 JS에서 사용가능하도록 한다. (이 설정을 할 경우 알아서 쿠키를 사용하게 된다)
  • ignoringRequestMatchers를 통해 발급되지 않는 url을 지정해 줄 필요가 있다 (로그인 등)
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
            .csrf(csrf -> csrf
                .csrfTokenRepository(
                    CookieCsrfTokenRepository.withHttpOnlyFalse()
                )
                .ignoringRequestMatchers(
                    "/auth/login",
                    "/auth/refresh"
                )
            )

            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
            );

        return http.build();
    }
}

 

 

단 CORS 설정시 주의해야 하는 부분이 있다. 설정을 잘못하면 CSRF를 켜도 무력화 될 수 있다. (CORS설정은 여기 : https://dean83.tistory.com/390)

allowCredentials 를 true로 설정했을 경우, allowedOrigins를 모든곳에서 허용해 버리면 안된다. (아래 예시처럼 하면 안된다)

config.setAllowCredentials(true);
config.setAllowedOrigins(List.of("*")); //*를 쓰면 안되고, 반드시 허용할 사이트를 명시해야 한다.

 

setAllowedHeaders 에 CSRF 헤더를 명시적으로 허용해 주어야 한다.

config.setAllowedHeaders(List.of(
    "Content-Type",
    "X-XSRF-TOKEN"
));

 

setAllowedMethods 또한 *로 주지 말고 값을 명시해야 한다.

config.setAllowedMethods(List.of(
    "GET", "POST", "PUT", "DELETE"
));

 

 

CORS + CSRF 의 SecurityFilterChain 설정예는 다음과 같다. 

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    http
        .cors(cors -> cors.configurationSource(request -> {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowCredentials(true);
            config.setAllowedOrigins(
                List.of("https://app.example.com")
            );
            config.setAllowedMethods(
                List.of("GET", "POST", "PUT", "DELETE")
            );
            config.setAllowedHeaders(
                List.of("Content-Type", "X-XSRF-TOKEN")
            );
            return config;
        }))

        .csrf(csrf -> csrf
            .csrfTokenRepository(
                CookieCsrfTokenRepository.withHttpOnlyFalse()
            )
        )

        .authorizeHttpRequests(auth -> auth
            .anyRequest().authenticated()
        );

    return http.build();
}