0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring Securityで403が出るのに原因が分からなかったときの話(CSRFが原因でした)

0
Last updated at Posted at 2026-03-22

問題

バックエンド単体でのテストでは問題なく動作していたにもかかわらず、フロントエンドと接続してブラウザ経由でリクエストを送ると、常に403 Forbiddenが返るようになりました。

原因の調査

ブラウザの開発者ツールで確認したところ、CSRFトークンはCookieおよびリクエストヘッダーの両方に含まれていました。

しかし、それにも関わらず403エラーが発生していたため、「サーバー側でトークンが正しく認識されていないのではないか」と考えました。

CSRFの設定を見直したところ、.csrfTokenRequestHandler(...) の設定が不足しており、リクエストヘッダーのトークンが正しく検証に使用されていなかったことが原因でした。

解決法

.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()) を追加し、リクエストヘッダーのCSRFトークンが正しく検証に利用されるようにしました。

SecurityConfig.java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  http
    .csrf(csrf -> csrf
      .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
      .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()) // ←追加
    )

なぜこの設定がないと403になるのか?

CSRF対策では「トークンを保存すること」と「リクエストから取り出して検証すること」の両方が必要です。

.csrfTokenRepository(...) はサーバーがトークンの保存先を定義する設定ですが、これはあくまで「トークンを発行してクライアントに渡す」までの役割しか持ちません。

一方で、実際のリクエスト時には「どこからトークンを取得するか」が別途必要になります。

.csrfTokenRequestHandler(...) は、サーバーが送られてきたトークンをどこからどのように取得するかを定義する役割を持っています。

この設定がない場合、トークン自体は存在していてもサーバーがそれを検出できず、不正なリクエストと判断されて403が返されます。

まとめ

今回の原因は、CSRFトークンが送られていないのではなく、サーバー側で正しく取得できていなかったことでした。
Cookieやヘッダーにトークンが存在していても、.csrfTokenRequestHandler(...) の設定がないと検証に使用されず、結果として403エラーになります。
CSRF対策は「トークンを発行すること」だけでなく、「リクエストからどう取得するか」まで含めて成立するものだと理解できました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?