미션 4: 취약점 대응 & 리팩토링
CsrfFilter를 이용한 CSRF 공격 대응
- CsrfToken 구현
- CsrfTokenRepository 구현 - HttpSessionCsrfTokenRepository
- CsrfToken 발급/저장/조회
- CsrfFilter 구현
- CsrfTokenRepository를 이용한 CsrfToken 검증
주요 클래스
HttpSecurity
HttpSecurityConfiguration
SecurityConfigurer
Customizer
@EnableWebSecurity
- HttpSecurity 구현
- @EnableWebSecurity, HttpSecurityConfiguration를 이용한 HttpSecurity 빈 등록
- csrf 필터를 configurer를 이용하여 설정
-
.formLogin()
메서드를 사용하여 폼 로그인 기능을 설정하고, UsernamePasswordAuthenticationFilter
를 자동으로 추가한다. -
.httpBasic()
메서드를 사용해 HTTP Basic 인증을 설정하고,BasicAuthenticationFilter
를 자동으로 추가한다. -
.securityContext()
메서드를 사용하여SecurityContextHolderFilter
자동으로 추가 - oauth2 리팩토링
- OAuth2AuthorizationRequestRedirectFilter 등록, OAuth2LoginAuthenticationFilter 등록
예시 코드
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public").permitAll() // /public 경로는 모두 허용
.anyRequest().authenticated()) // 그 외의 경로는 인증 필요
.formLogin(Customizer.withDefaults()) // 폼 로그인
.httpBasic(Customizer.withDefaults()); // HTTP Basic 인증
return http.build();
}
-
authorizeHttpRequests()
메서드 구현-
AuthorizeHttpRequestsConfigurer
를 이용한 설정 - 특정 경로에 대해 인증 없이 접근 가능하도록 설정하고, 나머지 요청에 대해서는 인증이 필요하도록 설정한다.
- 특정 경로에 대해서 권한에 따라 접근 가능하게 할지/말지를 설정한다
-
Auto Configuration을 통한 기본 SecurityFilterChain 설정
스프링 부트의 자동 설정을 통해 기본 SecurityFilterChain이 설정되도록 하고, 필요시 사용자가 새로운 SecurityFilterChain을 추가할 수 있도록 한다. 사용자가 새로운 SecurityFilterChain을 정의할 경우, 기본 보안 설정이 비활성화된다. 주요 클래스
- @ConditionalOnDefaultWebSecurity
- @DefaultWebSecurityCondition
- SpringBootWebSecurityConfiguration
- EnableWebSecurity
- AutoConfiguration을 이용하여
- 사용자가 SecurityFilterChain을 정의한 경우 기본 SecurityFilterChain이 설정된다.
- 사용자가 SecurityFilterChain을 정의하지 않은 경우 기본 SecurityFilterChain이 설정되지 않는다.
- CSRF 구현 방식에 대한 고민 (세션, 쿠키 둘 중 어디에 토큰을 저장할지?)
- HttpSecurity에서 필터의 순서를 어떻게 제어할지에 대한 고민
- 👉시큐리티에서는 httpSecurity.addFilter에서 OrderedFilter 생성. 또는 httpSecurity.addFilterAtOffsetOf에서 FilterOrderRegistration을 참조하여 필터 순서를 조정.
-
AuthorizeHttpRequestsConfigurer::hasRole
호출 시 roleHierarchy에 대한 의존성을 어떻게 관리할지에 대한 고민 - AuthorizationFilter에서 인증이 안 되었을 때 401을 던지는 것이 자연스러운가에 대한 고민
- 예외 상황에 따라서 어떻게 예외를 핸들링할지에 대한 고민
- HttpSecurity를 빈 등록 시 유연성이 떨어지는 문제 고민 (구현 완)
- SecurityConfigurer의
init
,configure
구분을 어떻게 하고 있는지? (구현 완)
sequenceDiagram
participant User
participant HackerSite
participant Bank
User ->> HackerSite: 악성 링크 클릭
HackerSite ->> Bank: POST 이체 요청 (자동 실행)
Bank -->> HackerSite: 성공 (세션 쿠키만으로 인증)
sequenceDiagram
participant User
participant HackerSite
participant Bank
User ->> Bank: 로그인
Bank -->> User: 세션 쿠키 + CSRF 토큰(HTML 숨김 필드)
User ->> HackerSite: 악성 링크 클릭
HackerSite ->> Bank: POST 이체 요청 (세션 쿠키만 포함)
Bank ->> Bank: 1. 세션에서 CSRF 토큰 조회
Bank ->> Bank: 2. 요청의 CSRF 토큰 비교
Bank -->> HackerSite: 403 Forbidden (토큰 없음)