カテゴリ: Spring認証(Spring Security) 更新日: 2025/11/24

CSRF対策が有効なフォームの作成方法を完全解説!Spring Securityの仕組みと設定ポイント

CSRF対策が有効なフォームの作成方法
CSRF対策が有効なフォームの作成方法

新人と先輩の会話形式で理解しよう

新人

「Spring SecurityのCSRF対策って何のためにあるんですか?フォームに何か追加しないとダメなんですか?」

先輩

「うん、フォームにCSRFトークンを追加しないと、Spring Securityがリクエストを受け付けてくれないよ。セキュリティ上の対策なんだ。」

新人

「フォームのセキュリティって言われてもピンと来ません…。具体的にどんな仕組みなんでしょうか?」

先輩

「じゃあまずは、CSRF攻撃が何かから順に説明していこうか。」

1. CSRFとは?(クロスサイトリクエストフォージェリの意味と脅威)

1. CSRFとは?(クロスサイトリクエストフォージェリの意味と脅威)
1. CSRFとは?(クロスサイトリクエストフォージェリの意味と脅威)

CSRF(シーエスアールエフ)とは、クロスサイトリクエストフォージェリと呼ばれるセキュリティ上の攻撃手法のことです。日本語では「サイト間リクエスト偽造」とも訳されます。

この攻撃は、ログイン中のユーザーが知らないうちに、意図しない操作をWebアプリケーションに対して実行させられるというものです。

たとえば、ユーザーが銀行の振込画面にログインしている状態で、別の悪意のあるサイトを開いてしまったとします。すると、その悪意あるサイトが自動で振込リクエストを送ってしまい、ユーザーが気づかないうちにお金が送金されるという危険性があります。

このように、セッションを利用したフォーム操作やアカウント更新処理などは、攻撃対象になりやすいのです。

そこで必要になるのがCSRF対策です。Spring Securityではこのような攻撃から守るために、デフォルトでCSRF保護が有効になっています。

フォームのセキュリティを確保するためには、正しいCSRFトークンを埋め込んだリクエストだけを受け付けるようにすることが重要です。

2. Spring SecurityにおけるCSRF保護の基本設定と自動有効化の仕組み

2. Spring SecurityにおけるCSRF保護の基本設定と自動有効化の仕組み
2. Spring SecurityにおけるCSRF保護の基本設定と自動有効化の仕組み

Spring Securityでは、CSRF対策が初期設定で有効になっており、開発者が特別な設定をしなくても、自動的に保護がかかるようになっています。

具体的には、POST・PUT・DELETEなどの変更系リクエストに対して、CSRFトークンの検証が行われるようになっています。

Spring Securityの内部では、HttpSecurityの中で以下のような設定が自動で適用されています。


@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.enable()) // デフォルトで有効なので明示的な記述は不要
            .authorizeHttpRequests(authz -> authz
                .anyRequest().permitAll()
            );
        return http.build();
    }
}

このように、特別な設定をしなくてもCSRF対策は機能しています。

ただし、フォームの送信時にはCSRFトークンを含めなければ、Spring Securityが403 Forbiddenを返すようになっています。

そのため、開発者はフォームの中にCSRFトークンをhidden項目として埋め込む必要があります。

このとき、Thymeleafを使用していない場合でも、Javaの@Controllerでトークンを取得し、HTMLに渡すことで対応が可能です。

以下は、pleiades + Gradleの開発環境で構築したSpringプロジェクトで、CSRFトークンをフォームに連携する方法の一部です。


@Controller
public class UserFormController {

    @GetMapping("/form")
    public String showForm(Model model, CsrfToken token) {
        model.addAttribute("_csrf", token);
        return "userForm";
    }
}

このようにしてJava側でトークンをModelに渡し、HTMLフォームに埋め込むことで、Spring SecurityによるCSRF保護が有効な安全なフォームを作成することができます。

次回は、実際のHTMLコードでCSRFトークンを埋め込む方法や、セッションとの連携方法を解説していきます。

3. CSRFトークンの仕組みと発行タイミング(セッション連携)

3. CSRFトークンの仕組みと発行タイミング(セッション連携)
3. CSRFトークンの仕組みと発行タイミング(セッション連携)

Spring Securityでは、ユーザーがログインしてセッションを開始したタイミングで、自動的にCSRFトークンの生成が行われます。このトークンはセッションごとに割り当てられ、サーバー側で保持されます。

このトークンは、ユーザーがフォームページへアクセスした際にJavaの@Controller経由でHTML側に渡され、フォームにhidden項目として埋め込まれることで、リクエストの正当性を証明する役割を果たします。

つまり、サーバー側で管理しているCSRFトークンと、フォームから送信されたトークンが一致すればリクエストは成功し、一致しなければ403 Forbiddenが返されます。これがSpring Security フォーム CSRF対策の基本です。

このように、トークンの発行と検証にはセッション情報が連携しており、ログイン後のセッションに依存した保護が行われている点がポイントです。

4. CSRFトークンのHTMLフォームへの埋め込み(Thymeleafなし)

4. CSRFトークンのHTMLフォームへの埋め込み(Thymeleafなし)
4. CSRFトークンのHTMLフォームへの埋め込み(Thymeleafなし)

Thymeleafを使っていれば、簡単に<form:form>タグでCSRFトークンを自動埋め込みできますが、今回は使用しない前提です。

そのため、Javaの@Controllerから明示的にトークンを取得し、HTMLテンプレートでhidden項目として手動で記述する必要があります。

以下は、フォームにCSRFトークンを埋め込むHTMLコードの例です。


<form action="/submit" method="post">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <input type="text" name="username" />
    <input type="submit" value="送信" />
</form>

ここで、${_csrf.parameterName}には_csrfオブジェクトのパラメータ名(通常は_csrf)、${_csrf.token}には実際のトークン値が格納されています。

これらは先ほどの@Controllerで次のように渡しています。


@GetMapping("/form")
public String showForm(Model model, CsrfToken token) {
    model.addAttribute("_csrf", token);
    return "userForm";
}

HTML側ではEL式(${ })でトークン値を参照し、明示的にフォームへ埋め込むことで、Spring Security フォーム CSRF対策が完成します。

5. トークンの検証処理と403 Forbiddenの理由

5. トークンの検証処理と403 Forbiddenの理由
5. トークンの検証処理と403 Forbiddenの理由

Spring Securityは、POSTやPUTなどのHTTPリクエストに対して、内部的にトークンの検証処理を行っています。

この検証は、リクエストヘッダーやフォーム内のhidden項目に含まれているトークンと、セッションに保存されているトークンを照合することで行われます。

照合に成功すればリクエストが通過し、失敗すると自動的に403 Forbiddenエラーが返されます。このエラーは、CSRFトークンが無効・未送信・不一致であることを示しています。

開発時によくある失敗例として、次のようなケースがあります:

  • フォームに<input type="hidden">でトークンを埋め込むのを忘れた
  • @ControllerCsrfTokenをModelに渡していない
  • HTML内で${_csrf.token}の記述を間違えている
  • JavaScriptで動的に生成したフォームにトークンを入れていない

このような場合は、403 Forbiddenが表示され、リクエストがブロックされます。

Spring Securityは、セッションが保持されている限り、常にサーバー側にCSRFトークンを保存しており、リクエストごとのトークン照合が自動で実行されるようになっています。

したがって、CSRF対策が有効なフォームを作成するには、必ず以下のポイントを意識してください。

  • トークンをHTMLに確実に埋め込むこと
  • @Controllerでトークンを忘れずにModelに追加すること
  • トークンの送信先が正しいエンドポイントであること

CSRFトークンの仕組みを理解し、正しくフォームに組み込むことで、403 Forbiddenエラーの回避と同時に、強固なセキュリティを実現できます。

6. Javaコードとフォーム連携による安全な送信処理

6. Javaコードとフォーム連携による安全な送信処理
6. Javaコードとフォーム連携による安全な送信処理

ここでは、CSRFトークンの仕組みを理解した上で、@ControllerとHTMLフォームを連携させた安全な送信処理を実装する方法を紹介します。

まず、@Controllerでトークンを取得してModelに渡します。そして、POSTリクエストを受け取るメソッドを用意して、フォームの送信処理を安全に行います。


@Controller
public class UserFormController {

    @GetMapping("/form")
    public String showForm(Model model, CsrfToken token) {
        model.addAttribute("_csrf", token);
        return "userForm";
    }

    @PostMapping("/submit")
    public String submitForm(@RequestParam("username") String username, Model model) {
        model.addAttribute("message", "ユーザー名:" + username + " を受け付けました。");
        return "result";
    }
}

次に、フォーム側のHTMLテンプレートには、次のようにCSRFトークンを埋め込みます。


<form action="/submit" method="post">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <label>ユーザー名:</label>
    <input type="text" name="username" />
    <input type="submit" value="送信" />
</form>

このように記述することで、Spring Security フォーム CSRF対策に準拠した安全な送信処理が可能となります。

7. CSRF除外設定のリスクと使い方(どうしても必要な場合の対応)

7. CSRF除外設定のリスクと使い方(どうしても必要な場合の対応)
7. CSRF除外設定のリスクと使い方(どうしても必要な場合の対応)

特定のエンドポイントでCSRFトークンを送らない必要があるケースもまれにあります。たとえば、外部APIからのPOSTリクエストやWebhook受信処理などです。

このような場合、Spring Security 設定方法として、CSRFトークン検証を一部のパスで除外する設定を行うことが可能です。


@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers("/webhook/**") // 除外するパスを指定
            )
            .authorizeHttpRequests(authz -> authz
                .anyRequest().permitAll()
            );
        return http.build();
    }
}

このようにignoringRequestMatchersを使って、特定のURLパスに対するCSRF除外設定を行うことができます。

ただし、この設定には重大なリスクが伴います。CSRF保護を無効化したエンドポイントは、外部からのリクエストを無制限に受け入れてしまう可能性があります。

特に、認証済みのセッションと連携している処理で除外設定を行うと、セキュリティホールになる危険性が高いです。

このため、CSRFを除外する際は以下の対策を併用しましょう。

  • トークン認証やAPIキーによる認可処理を追加する
  • 除外対象のエンドポイントを限定的に絞り込む
  • ログの出力IP制限を導入して不正アクセスを監視する

このように、CSRF除外設定は便利な反面、セキュリティ上の抜け道になりかねないため、最小限の使用に留めましょう。

8. 本番環境で安全に運用するためのベストプラクティス

8. 本番環境で安全に運用するためのベストプラクティス
8. 本番環境で安全に運用するためのベストプラクティス

最後に、本番環境でCSRF対策を含むセキュリティ運用を安全かつ安定して行うためのベストプラクティスを紹介します。

(1)セッショントークンのタイムアウトを設ける

CSRFトークンはセッションに紐づいているため、セッションが無効になるとトークンも無効になります。長時間放置されたセッションを自動で切断することで、不正利用を防止できます。

Spring Bootでは、application.propertiesなどで次のように設定します。


server.servlet.session.timeout=15m

これにより、最後のアクセスから15分が経過すると自動的にセッションが破棄されます。

(2)トークンのCookie管理との違いと選択基準

Spring SecurityのCSRFトークンは、通常はサーバー側セッションで管理されますが、Cookieにトークンを設定してフロントエンドと連携する方式も存在します。

Cookieベースの運用はSPA(Single Page Application)などで有効ですが、HTTPヘッダーでトークンを送信しないと検証エラーになるなど、実装が複雑になります。

今回のように、サーバーサイドでHTMLテンプレートを生成する構成では、セッション方式でのトークン管理のほうが初心者には扱いやすく、安全性も高いです。

(3)CSRFエラー発生時のユーザー対応

CSRFトークンが無効な場合、403 Forbiddenが返されてユーザーは困惑することがあります。

本番運用では、独自のエラーページを用意し、ユーザーに「再度ログインしてください」などの案内を表示すると親切です。

(4)セキュリティアップデートの継続的な適用

Spring Securityは継続的にアップデートされており、既知の脆弱性に対応するには定期的なライブラリ更新が不可欠です。

Gradleでバージョンを固定している場合でも、build.gradleでライブラリを見直す習慣を持ちましょう。

以上のようなポイントを意識することで、CSRF対策を含めたセキュリティ運用を本番環境で適切に行うことができます。

コメント
コメント投稿は、ログインしてください

まだ口コミはありません。

カテゴリの一覧へ
新着記事
New1
Spring認証(Spring Security)
ブラウザからのフォーム送信とは?HTTPリクエストの基礎を初心者向けに解説!
New2
Thymeleaf
ThymeleafでJavaScriptコメントを正しく書こう!初心者向け徹底解説
New3
SpringのDB操作
Spring Boot + MySQLでCRUDアプリを作ろう!初心者向けにデータベース操作を完全解説
New4
Springの基本
@SpringBootApplicationの仕組みと役割を徹底解説!初心者でもわかるSpring Bootの基本
人気記事
No.1
Java&Spring記事人気No1
SpringのWeb開発(Spring MVC)
ルーティングとは?基本概念(Spring MVCのURL制御を理解)
No.2
Java&Spring記事人気No2
Thymeleaf
Thymeleaf とは?初心者向けにThymeleafの基本を徹底解説
No.3
Java&Spring記事人気No3
Springの基本
application.properties と YAML の基本をやさしく解説!初心者向けSpring Boot設定ファイル入門
No.4
Java&Spring記事人気No4
Springの基本
Spring Bootの環境変数の設定方法をやさしく解説!初心者向けapplication.propertiesの使い方
No.5
Java&Spring記事人気No5
Springの基本
Spring Bootのデフォルトログ設定を徹底解説(Logback / SLF4J)
No.6
Java&Spring記事人気No6
SpringのDB操作
JPAの標準クエリメソッド(findById, findAll)を完全解説!初心者でもわかるデータ取得の基本
No.7
Java&Spring記事人気No7
SpringのWeb開発(Spring MVC)
ループ処理(th:each)の基本を完全ガイド!Thymeafの繰り返し処理の使い方
No.8
Java&Spring記事人気No8
Spring認証(Spring Security)
セッション管理の基本(@SessionAttributes)を完全解説!初心者でもわかるセッションの仕組み