CSRF 토큰 유지 - CsrfTokenRepository
- CsrfToken은 CsrfTokenRepository를 사용하여 영속화 하며, 구현체인 HttpSessionCsrfTokenRepository와 CookieCsrfTokenRepository를 지원
- 두 군데 중 원하는 위치에 토큰을 저장하도록 설정을 통해 지정 가능
- 세션에 토큰 저장 - HttpSessionCsrfTokenRepository
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
http.csrf(csrf -> csrf.csrfTokenRepository(repository));
return http.build();
}
- 기본적으로 토큰을 세션에 저장하기 위해 HttpSessionCsrfTokenRepository를 사용
- HttpSessionCsrfTokenRepository는 기본적으로 HTTP 요청 헤더인 X-CSRF-TOKEN 또는 요청 매개변수인 _csrf에서 토큰을 읽음
→ 토큰을 읽음 = 클라이언트가 서버에게 보낼 때 헤더에 CSRF를 담아서 보내야 함
- 쿠키에 토큰 저장 - CookieCsrfTokenRepository
- 아래 두 설정 중 하나만 사용 가능
- 기본값은 csrf.csrfTokenRepository(repository)
→ JS에서 직접 쿠키를 읽을 수 없음
- 기본값은 csrf.csrfTokenRepository(repository)
- 아래 두 설정 중 하나만 사용 가능
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
CookieCsrfTokenRepository repository = new CookieCsrfTokenRepository();
http.csrf(csrf -> csrf.csrfTokenRepository(repository));
http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
return http.build();
}
- JavaScript 기반 애플리케이션을 지원하기 위해 CsrfToken을 쿠키에 유지할 수 있으며 구현체로 CookieCsrfTokenRepository를 사용 가능
- CookieCsrfTokenRepository 는 기본적으로 XSRF-TOKEN 명을 가진 쿠키에 작성하고 HTTP 요청 헤더인 X-XSRF-TOKEN 또는 요청 매개변수인 _csrf에서 읽음
- JavaScript에서 쿠키를 읽을 수 있도록 HttpOnly를 명시적으로 false로 설정 가능
- JavaScript로 직접 쿠키를 읽을 필요가 없는 경우 보안을 개선하기 위해 HttpOnly를 생략을 권장
CSRF 토큰 처리 - CsrfTokenRequestHandler
- CsrfToken은 CsrfTokenRequestHandler를 사용하여 토큰을 생성 및 응답하고 HTTP 헤더 또는 요청 매개변수로부터 토큰의 유효성을 검증
- XorCsrfTokenRequestAttributeHandler와 CsrfTokenRequestAttributeHandler를 제공하며 사용자 정의 핸들러를 구현 가능
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
XorCsrfTokenRequestAttributeHandler csrfTokenHandler = new XorCsrfTokenRequestAttributeHandler();
http.csrf(csrf -> csrf.csrfTokenRequestHandler(csrfTokenHandler));
return http.build()
}
- “_csrf” 및 CsrfToken.class.getName()명으로 HttpServletRequest 속성에 CsrfToken을 저장하며 HttpServletRequest로부터 CsrfToken을 꺼내어 참조 가능
- 토큰 값을 요청 헤더(기본적으로 X-CSRF-TOKEN 또는 X-XSRF-TOKEN 중 하나) 또는 요청 매개변수(_csrf) 중 하나로부터 토큰의 유효성 비교 및 검증을 해결
- 클라이언트의 매 요청마다 CSRF 토큰 값(UUID)에 난수를 인코딩하여 변경한 CsrfToken 이 반환 되도록 보장
→ 세션에 저장된 원본 토큰 값은 그대로 유지 (이유는 바로 다음줄) - 헤더 값 또는 요청 매개변수로 전달된 인코딩 된 토큰은 원본 토큰을 얻기 위해 디코딩된 뒤 세션 혹은 쿠키에 저장된 영구적인 CsrfToken과 비교
CSRF 토큰 지연 로딩
- 기본적으로 Spring Security는 CsrfToken을 필요할 때까지 로딩을 지연시키는 전략을 사용
→ 따라서, CsrfToken은 HttpSession에 저장되어 있기 때문에 매 요청마다 세션으로부터 CsrfToken을 로드할 필요가 없어져 성능을 향상시킬 수 있음 - CsrfToken은 POST와 같은 안전하지 않은 HTTP 메서드를 사용하여 요청이 발생할 때와 CSRF 토큰을 응답에 렌더링하는 모든 요청에서 필요하기 때문에 그 외 요청에는 지연로딩하는 것을 권장
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
XorCsrfTokenRequestAttributeHandler handler = new XorCsrfTokenRequestAttributeHandler();
handler.setCsrfRequestAttributeName(null); //지연된 토큰을 사용하지 않고 CsrfToken 을 모든 요청마다 로드
http.csrf(csrf -> csrf.csrfTokenRequestHandler(handler));
return http.build()
}
'Language > Spring Security' 카테고리의 다른 글
SameSite (0) | 2024.07.29 |
---|---|
CSRF 통합 (0) | 2024.07.29 |
CSRF (Cross Site Request Forgery, 사이트 간 요청 위조) (0) | 2024.07.29 |
CORS (Cross Origin Resource Sharing, 교차 출처 리소스 공유) (0) | 2024.07.29 |
예외 필터 - ExceptionTranslationFilter() (0) | 2024.07.29 |