Files
2025-04-08 19:56:24 +09:00

141 lines
7.5 KiB
Markdown

스프링 부트에서 CSRF 설정을 URL 기반으로 세밀하게 제어하는 방법은 주로 `HttpSecurity` 설정을 통해 이루어집니다. 특정 URL 패턴에 대해서만 CSRF 보호를 활성화하거나 비활성화할 수 있습니다.
**핵심 아이디어:**
`HttpSecurity``csrf()` 메서드를 통해 CSRF 설정을 시작하고, `ignoringAntMatchers()`, `requireCsrfProtectionMatcher()` 등의 메서드를 사용하여 특정 URL 패턴을 설정합니다.
**설정 방법:**
`WebSecurityConfigurerAdapter`를 상속받는 설정 클래스 또는 `@Bean`으로 `SecurityFilterChain`을 정의하는 방식에서 `HttpSecurity`를 설정합니다.
**1. 특정 URL 패턴에 대해 CSRF 보호 비활성화:**
```java
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 보호를 유지할 수 있습니다.
```java
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()`로 제외했던 패턴 중 일부에 대해 다시 활성화할 수 있습니다. (일반적인 사용 사례는 아닐 수 있습니다.)
```java
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 보호를 활성화하거나 비활성화할 수 있습니다. 보안상의 영향을 충분히 고려하여 설정을 적용해야 합니다.