Files
spring-boot-examples/docs/security/11_csrf.md
2025-04-08 19:56:24 +09:00

7.5 KiB

스프링 부트에서 CSRF 설정을 URL 기반으로 세밀하게 제어하는 방법은 주로 HttpSecurity 설정을 통해 이루어집니다. 특정 URL 패턴에 대해서만 CSRF 보호를 활성화하거나 비활성화할 수 있습니다.

핵심 아이디어:

HttpSecuritycsrf() 메서드를 통해 CSRF 설정을 시작하고, ignoringAntMatchers(), requireCsrfProtectionMatcher() 등의 메서드를 사용하여 특정 URL 패턴을 설정합니다.

설정 방법:

WebSecurityConfigurerAdapter를 상속받는 설정 클래스 또는 @Bean으로 SecurityFilterChain을 정의하는 방식에서 HttpSecurity를 설정합니다.

1. 특정 URL 패턴에 대해 CSRF 보호 비활성화:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers(
                    new AntPathRequestMatcher("/api/public/**"), // /api/public/으로 시작하는 모든 요청에 대해 CSRF 비활성화
                    new AntPathRequestMatcher("/h2-console/**") // H2 콘솔 접근 시 CSRF 비활성화 (개발 환경)
                    // 추가적인 URL 패턴 설정 가능
                )
            )
            .authorizeHttpRequests(auth -> auth
                .anyRequest().permitAll() // 예시: 모든 요청 허용
            );
        return http.build();
    }
}
  • .csrf(csrf -> ...): CSRF 설정을 시작합니다.
  • .ignoringRequestMatchers(...): 주어진 RequestMatcher와 일치하는 요청에 대해서는 CSRF 보호를 비활성화합니다.
  • new AntPathRequestMatcher("/api/public/**"): Ant 스타일의 URL 패턴을 사용하여 /api/public/으로 시작하는 모든 경로를 매칭합니다.
  • new AntPathRequestMatcher("/h2-console/**"): H2 콘솔 경로는 일반적으로 개발 환경에서 사용되므로 CSRF 보호를 비활성화하는 경우가 많습니다.
  • 여러 개의 ignoringRequestMatchers()를 사용하여 다양한 URL 패턴을 설정할 수 있습니다.

2. 특정 HTTP 메서드에 대해서만 CSRF 보호 비활성화:

특정 URL 패턴에 대해 특정 HTTP 메서드(예: GET 요청)에 대해서만 CSRF 보호를 비활성화하고, 데이터를 변경하는 요청(POST, PUT, DELETE)에는 CSRF 보호를 유지할 수 있습니다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.util.Arrays;
import java.util.List;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        List<RequestMatcher> withoutCsrf = Arrays.asList(
            new AntPathRequestMatcher("/api/public/**", "GET"), // /api/public/으로 시작하는 GET 요청에 대해 CSRF 비활성화
            new AntPathRequestMatcher("/some/readonly/path", "GET")
            // 추가적인 GET 요청 패턴 설정 가능
        );

        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers(withoutCsrf.toArray(new RequestMatcher[0]))
            )
            .authorizeHttpRequests(auth -> auth
                .anyRequest().permitAll() // 예시: 모든 요청 허용
            );
        return http.build();
    }
}
  • new AntPathRequestMatcher("/api/public/**", "GET"): /api/public/으로 시작하고 HTTP 메서드가 GET인 요청만 매칭합니다.

3. 특정 URL 패턴에 대해서만 CSRF 보호 활성화 (기본 설정 외 추가):

기본적으로 CSRF 보호는 활성화되어 있지만, 특정 URL 패턴에 대해서만 명시적으로 활성화하거나, ignoringRequestMatchers()로 제외했던 패턴 중 일부에 대해 다시 활성화할 수 있습니다. (일반적인 사용 사례는 아닐 수 있습니다.)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.util.Arrays;
import java.util.List;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        List<RequestMatcher> requireCsrf = Arrays.asList(
            new AntPathRequestMatcher("/admin/**") // /admin/으로 시작하는 요청에 대해 CSRF 활성화 (명시적)
            // 추가적인 활성화 패턴 설정 가능
        );

        http
            .csrf(csrf -> csrf
                // .ignoringRequestMatchers(...) // 특정 패턴 비활성화 설정이 있을 경우
                .requireCsrfProtectionMatcher(request -> {
                    // 기본적으로 POST, PUT, DELETE 요청에 대해 CSRF 보호를 적용하고,
                    // requireCsrf 리스트에 있는 패턴에 대해서도 적용
                    boolean defaultMatch = !request.getMethod().equalsIgnoreCase("GET");
                    return defaultMatch || requireCsrf.stream().anyMatch(matcher -> matcher.matches(request));
                })
            )
            .authorizeHttpRequests(auth -> auth
                .anyRequest().permitAll() // 예시: 모든 요청 허용
            );
        return http.build();
    }
}
  • .requireCsrfProtectionMatcher(RequestMatcher): CSRF 보호를 적용할 요청을 결정하는 RequestMatcher를 설정합니다.
  • 위 예시에서는 기본적으로 GET 요청이 아닌 경우 CSRF 보호를 적용하고, 추가적으로 /admin/** 패턴과 일치하는 모든 요청에 대해 CSRF 보호를 적용합니다.

주의 사항:

  • CSRF 보호를 특정 URL에 대해 비활성화하는 것은 보안 위험을 증가시킬 수 있습니다. 신중하게 결정해야 하며, 정말로 CSRF 보호가 불필요한 경우에만 적용해야 합니다.
  • RESTful API를 개발하는 경우, Stateless 특성을 유지하기 위해 CSRF 대신 다른 보안 메커니즘(예: JWT 기반 인증)을 사용하는 것을 고려할 수 있습니다. 이 경우 CSRF를 비활성화할 수 있습니다.
  • H2 콘솔과 같은 개발 도구에 대한 CSRF 비활성화는 개발 환경에서 편의를 위해 사용될 수 있지만, 프로덕션 환경에서는 보안을 위해 접근 제어를 설정하는 것이 좋습니다.

결론:

스프링 부트에서 URL 기반으로 CSRF 설정을 제어하려면 HttpSecurity 설정을 활용하여 ignoringRequestMatchers() 또는 requireCsrfProtectionMatcher() 메서드를 사용하여 원하는 URL 패턴에 따라 CSRF 보호를 활성화하거나 비활성화할 수 있습니다. 보안상의 영향을 충분히 고려하여 설정을 적용해야 합니다.