웹 애플리케이션 개발에서 보안은 핵심 요소이며, 특히 사용자 데이터를 다루는 서비스에서는 더욱 중요합니다. CSRF(Cross-Site Request Forgery)는 웹 애플리케이션의 보안 취약점을 노리는 대표적인 공격 방식 중 하나로, 이를 방어하는 것은 안전한 애플리케이션 운영에 필수적입니다. 스프링 부트 3(Spring Boot 3)에서는 CSRF 공격 방어를 위한 다양한 보안 메커니즘이 기본 제공되며, 이를 통해 보안을 강화할 수 있습니다. 이 글에서는 CSRF의 개념과 동작 원리, 스프링 부트 3에서의 CSRF 보호 구현 방법, 그리고 실무에 적용할 수 있는 구체적인 예시를 다룹니다.
1. CSRF란 무엇인가?
CSRF(Cross-Site Request Forgery)는 인증된 사용자가 의도하지 않은 요청을 서버에 보내도록 속이는 공격 방식입니다. 공격자는 피해자가 이미 로그인한 상태라는 점을 악용해 악성 스크립트를 포함한 요청을 서버에 보내고, 결과적으로 피해자의 권한으로 서버 리소스를 조작하게 만듭니다.
CSRF 공격의 주요 특징:
- 사용자의 권한 악용: 공격은 사용자의 세션 또는 인증 정보를 이용합니다.
- 숨겨진 요청: 사용자는 자신이 요청을 보냈다는 사실을 인지하지 못합니다.
- HTTP 요청 조작: GET, POST 등 HTTP 메서드 요청이 변조됩니다.
CSRF 예시:
- 공격자가 악성 링크를 이메일로 전송하여 피해자가 클릭하게 유도.
- 피해자가 링크를 클릭하면 악성 요청이 피해자의 세션으로 서버에 전송.
- 서버는 요청이 합법적이라 판단하고 데이터 조작 또는 민감한 정보 유출이 발생.
2. 스프링 부트 3의 CSRF 보호 기본 설정
스프링 부트 3는 CSRF 보호 기능을 기본적으로 활성화합니다. Spring Security 모듈을 통해 요청이 인증된 사용자의 것인지 확인하고, 비정상적인 요청을 차단하는 메커니즘을 제공합니다. 이 기능은 주로 CSRF 토큰을 활용하여 작동합니다.
CSRF 보호 동작 방식:
- 클라이언트가 서버에 요청을 보낼 때 서버는 CSRF 토큰을 생성하고 이를 응답의 일부로 클라이언트에 전달.
- 클라이언트는 이후 요청마다 CSRF 토큰을 포함시켜 서버에 보냄.
- 서버는 요청에 포함된 CSRF 토큰이 유효한지 확인하여 요청을 처리.
3. 스프링 부트 3에서 CSRF 보호 구현하기
스프링 부트 3에서 CSRF 보호를 설정하고 사용하는 방법을 단계별로 살펴보겠습니다.
3.1. 기본 CSRF 보호 활성화
스프링 부트 3에서는 기본적으로 CSRF 보호가 활성화되어 있습니다. 보안 설정 파일에서 이를 명시적으로 확인할 수 있습니다.
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf() // CSRF 보호 활성화
.and()
.authorizeHttpRequests()
.requestMatchers("/public/**").permitAll() // 공개 경로 설정
.anyRequest().authenticated(); // 나머지 요청은 인증 필요
return http.build();
}
3.2. CSRF 비활성화 (특정 상황)
CSRF 보호가 필요 없는 REST API의 경우, 비활성화할 수 있습니다. 예를 들어, JSON 형식으로 통신하는 RESTful 서비스에서는 CSRF 보호가 필요하지 않을 수 있습니다.
http
.csrf().disable()
.authorizeHttpRequests()
.anyRequest().authenticated();
3.3. CSRF 토큰 생성 및 전달
HTML 폼에서 CSRF 토큰을 포함하려면 Spring Security의 Thymeleaf 지원을 사용할 수 있습니다.
<form action="/submit" method="post">
<input type="hidden" name="_csrf" value="${_csrf.token}" />
<button type="submit">Submit</button>
</form>
4. 실무 예제: CSRF 보호 적용하기
예제 1: 사용자 인증 요청 보호
사용자가 로그인하는 폼에 CSRF 토큰을 추가해 보호합니다.
http
.csrf()
.and()
.formLogin()
.loginPage("/login")
.permitAll();
예제 2: 특정 엔드포인트에 CSRF 보호 적용
관리자 페이지와 같은 민감한 엔드포인트에만 CSRF 보호를 적용하고, 나머지는 비활성화합니다.
http
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/admin/**"))
.and()
.authorizeHttpRequests()
.requestMatchers("/admin/**").authenticated();
예제 3: SPA와 CSRF 보호
React, Angular와 같은 SPA 프런트엔드에서 CSRF 토큰을 API 호출 시 헤더에 포함하도록 구현합니다.
fetch('/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify(data)
});
5. CSRF 보호를 위한 베스트 프랙티스
- 토큰 주기적 갱신: CSRF 토큰은 주기적으로 갱신하여 사용해야 안전합니다.
- GET 요청은 읽기 전용: 민감한 작업은 POST, PUT, DELETE 요청으로 처리하고, GET 요청은 데이터 조회용으로만 사용합니다.
- 쿠키 보안 강화: SameSite 속성을 Strict 또는 Lax로 설정해 쿠키를 보호합니다.
스프링 부트 3는 CSRF 공격으로부터 애플리케이션을 효과적으로 보호할 수 있는 강력한 기능을 제공합니다. 개발자는 애플리케이션 요구 사항에 맞게 CSRF 설정을 적절히 조정하고, 보안 기능을 최대한 활용해야 합니다. 이 글이 CSRF 보호와 스프링 부트 3의 사용에 대한 이해를 높이는 데 도움이 되었기를 바랍니다.
'스프링 부트3' 카테고리의 다른 글
스프링 부트 3의 Reactive Programming (0) | 2024.12.06 |
---|---|
스프링 부트 3에서 메일 발송 구현 (0) | 2024.12.06 |
스프링 부트 3의 WebFilter 구현 (0) | 2024.12.06 |
스프링 부트 3에서 RestTemplate 대체하기 (0) | 2024.12.06 |
스프링 부트 3와 NoSQL 데이터베이스 (0) | 2024.12.06 |