【実務・中級編】Spring SecurityにおけるCSRFトークン生成と検証の自動化実装 – アプリケーションセキュリティ & 安全な開発防御ガイド

Spring SecurityのCSRF対策:なぜ「無効化」が地獄への入り口なのか

現場でコードレビューをしていると、若手エンジニアから「REST APIだからCSRF対策は不要ですよね? セッション管理もStatelessだし」という言葉を耳にすることがある。その瞬間、私は深くため息をつき、こう諭す。「その認識が、君のサービスを数分で乗っ取られる脆弱性の温床になるんだ」と。

今日は、Spring SecurityにおけるCSRF(Cross-Site Request Forgery)トークンの本質と、なぜそれが「自動化」されているのか、そしてREST APIで安易にそれを捨てることがどれほど危険な賭けなのかを、泥臭いインシデントの知見を交えて解説する。

1. CSRFの本質:ブラウザの「お節介」を逆手に取る

CSRFは、ユーザーが認証済みの状態で、攻撃者が用意した罠サイトにアクセスした際、ブラウザが勝手にCookieを送信してしまう性質を悪用する。

攻撃者のシナリオ(PoCイメージ):
1. ユーザーが銀行サイトにログイン中。
2. 攻撃者が仕込んだブログの隠し画像タグ `` をブラウザが読み込む。
3. ブラウザはセッションCookieを勝手に付けてリクエストを投げる。
4. サーバー側は「セッションが有効だから本人の指示だ」と判断し、送金を実行する。

Spring Securityが提供するCSRFトークンは、この「リクエスト元が正規の画面(アプリケーション)であること」を証明するための、一種の「使い捨てパスポート」だ。

2. Spring Securityによる自動化の仕組み

Spring Securityは、`CsrfFilter`を通じて、POST/PUT/DELETEなどの非安全なメソッドに対し、トークンの検証を強制する。

基本的な設定

デフォルトでは、`HttpSessionCsrfTokenRepository` が使用され、サーバー側のセッション内にトークンが保持される。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// デフォルトでCSRF対策は有効。わざわざ無効化する必要はない
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// AngularやReactなどのフロントエンドがCookieから読み取れるよう、HttpOnlyをfalseにするのがREST APIの定石
);
return http.build();
}
}

なぜ `withHttpOnlyFalse()` なのか?
SPA(Single Page Application)構成では、フロントエンドのJavaScriptからトークンを読み取り、リクエストヘッダー(例: `X-XSRF-TOKEN`)に含める必要があるからだ。ここで「セキュリティ的に怪しい」と迷う必要はない。このトークン自体は機密情報ではないため、漏洩しても攻撃者はそれ単体では何もできない(CookieのセッションIDとペアでなければ無意味だからだ)。

3. 「REST APIで無効化」という甘い罠

「JWTを使っているからCSRFは不要」と考えるのは危険だ。特に、ブラウザが自動的に送出するCookieにJWTを格納している場合は、完全にCSRFの対象となる。

もし、どうしてもCSRF対策を無効化せざるを得ない(厳密な制限がある)場合でも、せめて特定のパスに限定すべきだ。

// 絶対に推奨しないが、APIのログインエンドポイントのみを対象にする場合の例
http.csrf(csrf -> csrf
.ignoringRequestMatchers(“/api/v1/auth/”)
);

4. フロントエンドでの実装サンプル(JavaScript)

サーバーから送られてきたトークンを、クライアント側でどう扱うか。Axiosを使っているなら、Interceptorで自動付与するのがスマートだ。

import axios from ‘axios’;

// サーバーがCookieにセットしたXSRF-TOKENを読み取り、ヘッダーに自動付与
const apiClient = axios.create({
withCredentials: true // Cookieを送信するために必須
});

apiClient.interceptors.request.use((config) => {
const token = document.cookie.replace(/(?:(?:^|.;\s)XSRF-TOKEN\s=\s([^;]).$)|^.$/, “$1”);
if (token) {
config.headers[‘X-XSRF-TOKEN’] = token;
}
return config;
});

セキュリティチーフからの「最後の警告」

インシデント対応の現場でよく見るのは、「開発工数を減らすためにセキュリティ機能を無効化する」という現場の判断だ。しかし、CSRF対策のコードを数行書くコストと、全ユーザーのデータが改ざんされた後のフォレンジック調査・謝罪会見のコストを天秤にかけてほしい。

1. CSRFトークンは「自動生成・自動検証」をデフォルトとする。
2. REST APIであっても、Cookieベースの認証なら絶対にCSRF対策を外さない。
3. もし「仕組みが分からないから無効にする」と言い出すエンジニアがいれば、それは君のチームが学習する良い機会だ。一緒にドキュメントを読み解こう。

セキュリティは「完成品」ではなく「継続的な規律」だ。Spring Securityの強力なデフォルト設定は、我々エンジニアを守るための最初の防壁に過ぎない。これを正しく理解し、使いこなすことこそが、プロフェッショナルへの第一歩だ。

コメント

タイトルとURLをコピーしました