はじめに
Spring Security でCookieによるCSRF対策を実施している場合、クライアント側ではCookieの"XSRF-TOKEN"を読み取ります。
しかし、ログイン認証処理後やログアウト後は、Cookieがクリアされてしまいます。
それにより、ログイン後にCookieを取得することが出来なく、処理を続行することができません。
デフォルトの設定だとうまくいきませんのでひと工夫が必要です。
解決策
解決策は、公式サイトに書いてあります。
https://spring.pleiades.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa
CookieにCSRFトークンを出力するためのフィルタを新たに作成
※公式サイトより一部引用
final class CsrfCookieFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
// Render the token value to a cookie by causing the deferred token to be loaded
csrfToken.getToken();
filterChain.doFilter(request, response);
}
}
上記クラスをSecurityConfigに追加
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.csrf((csrf) -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// ...
)
.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class); // 新たに作成したFilterを追加
return http.build();
}
}
これにより、ログイン後やログアウト後にもCSRFトークンがCookieに設定されるようになります。
最後に
Spring SecurityのCSRF対策機能では、シングルページアプリケーションやRestAPIの場合、Cookieを利用してCSRF対策を行うことが必須となりますが、ここで述べた問題だけでなく、シングルページアプリケーションやRestAPIにおけるSpring Security でのCSRF対策でも述べた問題もあり、デフォルトの状態だと動かなかったりします。
前述の通り公式サイトに書いてはいるのですが、それ以外にはなかなか情報がなかったため、こちらに記載しました。