12 人が閲覧(直近 30 日) Spring

Spring Securityとは?認証・認可の仕組みと基本設定を7.1で解説

Spring Securityとは?認証・認可の仕組みと基本設定を7.1で解説

Spring Securityは、Springで作るアプリケーションに認証(誰がアクセスしているかの確認)と認可(その人に何を許すかの判定)、CSRFなどの一般的な攻撃への対策を加えるフレームワークです。公式リファレンスは「authentication, authorization, and protection against common attacks」を提供するものと定義しています。2026年10月時点の最新安定版は7.1.1で、Spring Boot 4.1.1が標準で取り込む版です。この記事では、Spring Boot 4.1.1・JDK 25で実際に起動して確かめた挙動をもとに、仕組みと基本設定、7系で変わった点を説明します。

まとめ:Spring Securityの役割と最初に押さえる5点

  • 役割:認証・認可・攻撃対策の3つ。ログイン画面、権限による画面やAPIの出し分け、CSRF対策、セキュリティヘッダーの付与をまとめて担う。
  • 仕組み:アプリ本体より前に並ぶ「フィルタの列」(SecurityFilterChain)がリクエストを検査する。コントローラーに届く前に401や403で止める。
  • 依存を足すだけで有効:Spring Bootでは spring-boot-starter-security を追加した時点で全URLが認証必須になり、ログ出力されたパスワードでしか入れない。
  • 設定の書き方:SecurityFilterChain のBeanをラムダ式で書く。WebSecurityConfigurerAdapter や and() を使う旧記事のコードは7系では動かない。
  • 版:最新は7.1.1。6.5系の無償サポートは2026年6月30日に終了し、7.0系も2026年12月31日に終わる。新規は7.1系(Spring Boot 4.1系)で始める。

Spring Securityの役割:認証・認可・攻撃対策の3本柱

読み方は「スプリング・セキュリティ」です。Springプロジェクトの一つで、Webアプリ(サーブレット)とリアクティブ(WebFlux)の両方に対応します。Spring Boot自体はセキュリティ機能を持たず、Spring Securityを自動設定で組み込む役回りです。Bootが「既定の設定」を用意し、細かな規則はSpring Securityの設定で書く、と分担を覚えておくと混乱しません。

APIをBasic認証などで呼んだ場合、認証と認可は失敗したときのHTTPステータスが違います。この違いを押さえておくと、エラーの切り分けが速くなります。ブラウザからのフォームログインでは、未認証は401ではなくログイン画面への302転送になります。

機能 問い 失敗時 代表的な部品
認証 あなたは誰か 401(ブラウザは302) AuthenticationManager
認可 それをしてよいか 403 Forbidden AuthorizationManager
攻撃対策 正規の画面からの操作か リクエストを拒否 CsrfFilter・HeaderWriterFilter

2025年11月の7.0では、OAuth 2.0の認可サーバーを作るSpring Authorization ServerがSpring Security本体に取り込まれ、多要素認証(MFA)の仕組みも加わりました。トークンを発行する側と検証する側の両方を同じプロジェクトで扱えるようになっています。

リクエストがSpring Securityを通る仕組み

FilterChainProxyとSecurityFilterChainの関係

Spring Securityの入口としてサーブレットコンテナに登録されるのは、DelegatingFilterProxy という1本のフィルタです。これがSpringのBeanである FilterChainProxy に処理を渡し、FilterChainProxy はURLに合う SecurityFilterChain を1つ選んで、その中のフィルタを順に実行します。Spring Boot 4.1.1の既定構成では16本のフィルタが並び、CSRFの検査、ログイン処理、例外の変換、最後の認可判定までがこの列の中で終わります。各フィルタの順序と差し込み方はSecurityFilterChainとは?Spring Securityのフィルタ実行順序と設定例で実測しています。

認証の部品:AuthenticationManager・UserDetailsService・PasswordEncoder

ログイン処理のフィルタは、受け取ったユーザー名とパスワードを AuthenticationManager に渡します。標準の実装 ProviderManager は、登録された AuthenticationProvider に順に確認を頼みます。ID・パスワード方式の場合は DaoAuthenticationProvider が UserDetailsService でユーザーを読み出し、PasswordEncoder でハッシュ値を照合します。

PasswordEncoder は spring-security-crypto モジュールにあります。PasswordEncoderFactories.createDelegatingPasswordEncoder() で作ると、BCryptでハッシュ化し、方式名を接頭辞として付けます。7.1.1で実行した出力は次のとおりです。

{bcrypt}$2a$10$rqs..pkDunT234Yj1dAvPet1jSATG95WD82DeGHNPQYUH2nJC.ag2

接頭辞があるので、将来ほかの方式へ移っても古いハッシュを照合できます。逆に、接頭辞の無い値を照合しようとすると IllegalArgumentException(「each password must have a password encoding prefix」)で止まります。平文を保存していた旧システムから移行するときにまず当たるエラーです。独自の AuthenticationProvider を作る手順はSpring Bootの認証実装:カスタムAuthenticationProviderの作り方とテストにまとめています。

認証結果の置き場:SecurityContextHolder

認証に成功すると、結果の Authentication が SecurityContextHolder に入ります。コントローラーやサービスからは次のように取り出せます。

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return auth.getName() + " " + auth.getAuthorities();

7.1.1で、ロールUSERのユーザーaliceがパスワードでログインした状態で実行すると、権限一覧は [ROLE_USER, FactorGrantedAuthority [authority=FACTOR_PASSWORD, ...]] になりました。7系では、どの方法で本人確認したかを示す FactorGrantedAuthority が認証時に自動で追加されます。多要素認証はこの値を使って「パスワードとワンタイムトークンの両方が済んでいるか」を判定します。権限一覧を文字列で比べている既存コードは、7系に上げると要素が1つ増える点に注意してください。

認可の部品:AuthorizationManager(AccessDecisionManagerの後継)

アクセスを許すかどうかは AuthorizationManager が判定します。公式ドキュメントは AuthorizationManagerが「AccessDecisionManagerとAccessDecisionVoterの両方を置き換える」と説明しています。独自の判定は、次のようにラムダ1つで書けます(例はログイン済みの利用者に日本時間の9時以上18時未満だけ許可する規則)。

AuthorizationManager<RequestAuthorizationContext> officeHours() {
    return (authentication, context) -> {
        int hour = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Tokyo")).getHour();
        boolean loggedIn = new AuthenticationTrustResolverImpl().isAuthenticated(authentication.get());
        boolean allowed = loggedIn && hour >= 9 && hour < 18;
        return new AuthorizationDecision(allowed);
    };
}

未ログインの利用者にも匿名の Authentication が入っており、その isAuthenticated() は true を返します。authentication.get().isAuthenticated() だけで判定すると匿名でも通ってしまうため、AuthenticationTrustResolverImpl で匿名を除外しています。7.1.1で確かめると、未ログインは401、aliceは200でした。LocalTime.now() はサーバーのタイムゾーンに従うので、UTCで動くコンテナでは時刻帯がずれます。タイムゾーンは明示してください。

古い解説にある AccessDecisionManager や AccessDecisionVoter は、7.0で spring-security-access という別モジュールに移されました。Spring Boot 4.1.1のスターターが取り込むjarは config・core・crypto・web の4つで、実際にビルドした成果物にも AccessDecisionManager は入っていませんでした。旧方式のコードをそのまま貼るとコンパイルできません。

依存を追加しただけで起きること(Spring Boot 4.1.1で実測)

設定を何も書かずに、/hello を返すだけのアプリへ spring-boot-starter-security を加えて起動しました。起動ログには次の2行が出ます。

Using generated security password: d9fce44d-e604-4ab3-9509-e1449d0db1f6
This generated password is for development use only. Your security configuration must be updated before running your application in production.

ユーザー名は user 固定で、パスワードは起動のたびに変わります。Spring Bootのドキュメントどおり、spring.security.user.name と spring.security.user.password で固定値に変えられます。この状態でcurlから叩いた結果が次の表です。

リクエスト 結果
GET /hello(Acceptヘッダーなし) 401・WWW-Authenticate: Basic
GET /hello(Accept: text/html) 302で /login へ転送
GET /login 200・ログイン画面(_csrf入り)
GET /hello(Basic認証 user) 200
GET /hello(パスワード誤り) 401
POST(Basic認証・CSRFトークンなし) 401

ブラウザからはログイン画面、APIクライアントからはBasic認証と、Acceptヘッダーで応答が分かれます。CSRFトークンの無いPOSTが403でなく401になるのは、この既定構成ではCSRFの検査がBasic認証のフィルタより先に動くためです。拒否された時点ではまだ認証されておらず、そのあとのエラー画面(/error)への転送でもBasic認証は実行されないので、匿名のまま認可に失敗して401になります(仕組みは7001の記事で追っています)。どの応答にも X-Frame-Options: DENY、X-Content-Type-Options: nosniff、Cache-Control: no-cache, no-store, max-age=0, must-revalidate が付きました。HTTPで起動したためHSTSヘッダーは付いていません。

この既定構成は開発用です。SecurityFilterChain のBeanを定義するとBootの既定のフィルタ構成は外れますが、生成パスワードのユーザーは残ります。UserDetailsService のBeanを定義すると、生成パスワードのログは出なくなりました(次の章の設定で確認)。

基本設定:SecurityFilterChainでのURL別の認可規則

Mavenなら依存は1つです。Spring Boot 4.1.1の親POMを使えば版の指定は要りません。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

次の設定は、/public/** を公開、/admin/** をADMINロール限定、それ以外をログイン必須にし、メモリ上に2人のユーザーを作ります。

@Configuration
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated())
            .formLogin(Customizer.withDefaults())
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Bean
    UserDetailsService users(PasswordEncoder encoder) {
        return new InMemoryUserDetailsManager(
            User.withUsername("alice").password(encoder.encode("alice-pass")).roles("USER").build(),
            User.withUsername("bob").password(encoder.encode("bob-pass")).roles("USER", "ADMIN").build());
    }
}

alice・bobのパスワードは動作確認用の固定値で、本番ではDBやIDプロバイダーから読み込みます。/public/hello・/me・/admin/panel を返すだけのコントローラーを置き、起動してBasic認証で叩いた結果です。

URL 未ログイン alice(USER) bob(USER・ADMIN)
/public/hello 200 200 200
/me 401 200 200
/admin/panel 401 403 200

ログインしていなければ401、ログイン済みでも権限が足りなければ403です。hasRole("ADMIN") は権限 ROLE_ADMIN を探すので、DBに権限を保存するときは接頭辞 ROLE_ を付けるか、hasAuthority を使います。規則は上から順に評価され、最初に一致したものが使われます。anyRequest() を先頭に書くと、起動時に IllegalStateException: Can't configure requestMatchers after anyRequest で止まります。

メソッド単位の認可:@PreAuthorizeと@Secured

URLではなくメソッドに条件を付けるには @EnableMethodSecurity を付け、@PreAuthorize("hasRole('ADMIN')") などを書きます。ここで間違えやすいのが @Secured です。@EnableMethodSecurity の既定は prePostEnabled だけが有効で、securedEnabled と jsr250Enabled は明示的に有効化が必要です。

設定 @PreAuthorize(ADMIN限定) @Secured(“ROLE_ADMIN”)
@EnableMethodSecurity aliceは403 aliceも200
@EnableMethodSecurity(securedEnabled = true) aliceは403 aliceは403

エラーも警告も出ずに素通りするので、テストで権限の無いユーザーを流さない限り気づけません。公式も @PreAuthorize の方が表現力が高いとして推奨しています。新しく書くなら @PreAuthorize に揃え、既存の @Secured が残っているプロジェクトでは securedEnabled = true が付いているかを最初に確認してください。

Spring Security 7で動かなくなった旧コード

「Spring Security 入門」で検索して出てくる解説には、5系の書き方がまだ多く残っています。7系で使えないものを並べます。

旧い書き方 変わった版 今の書き方
extends WebSecurityConfigurerAdapter 6.0で削除 SecurityFilterChainのBean
antMatchers() / mvcMatchers() 6.0で削除 requestMatchers()
authorizeRequests() 7.0で削除 authorizeHttpRequests()
.and() でつなぐ設定 7.0で削除 ラムダ式(Customizer)
AccessDecisionManager / Voter 7.0で別モジュールへ AuthorizationManager
AuthorizationManager#check 7.0で削除 AuthorizationManager#authorize
javax.servlet.* 6.0から jakarta.servlet.*

出典は7.0のWhat’s Newと、WebSecurityConfigurerAdapter の削除を記した6.0.0-RC1のリリースノートです。コピーしたコードがコンパイルできないときは、まずこの表の左列が含まれていないかを見てください。Spring Boot側の変更はSpring Boot 4とは?最新バージョン4.1の変更点・新機能とSpring Boot 3との違いで扱っています。

バージョンとサポート期限:6.5系を使い続けるかの判断

Springのサポート表(api.spring.io のgenerations)で2026年10月18日に確認した値です。最新パッチはMaven Centralで確認しました。

系列 対応Boot 最新パッチ 無償サポート終了 商用サポート終了
7.2.x 4.2.x 7.2.0-M2(開発版) 2027-12-31 2028-12-31
7.1.x 4.1.x 7.1.1 2027-07-31 2028-07-31
7.0.x 4.0.x 7.0.7 2026-12-31 2027-12-31
6.5.x 3.5.x 6.5.11(無償の最終) 2026-06-30 2032-06-30

6.5系の無償サポート終了は実害として表れています。2026年8月20日に公表されたCVE-2026-41707(DPoPの使い回し防止キャッシュを大量の要求で押し出し、盗んだ証明を再利用できる脆弱性)は、7.1.0・7.0.0〜7.0.6・6.5.0〜6.5.11が影響を受けます。修正版は7.1.1と7.0.7が無償で出ましたが、6.5系の修正版6.5.12は商用サポート契約者向けだけです。DPoPを使っていなければこのCVEの影響はありません。ただし、今後見つかる脆弱性でも6.5系の修正版は商用サポート向けにしか出ない見込みです。商用サポートを契約しないなら、Spring Boot 3.5の運用は移行までのつなぎと位置づけ、4.1系(Spring Security 7.1系)への移行計画を立ててください。Bootの版ごとの期限はSpring Bootバージョン一覧とサポート期限(EOL)にまとめています。

採用すべき場面と、Spring Securityだけで済ませない方がよい場面

Spring BootでWebアプリやAPIを作るなら、認証・認可は自作せずSpring Securityを使うべきです。セッション固定攻撃への対策、CSRFトークン、セキュリティヘッダーは既定で有効になり、パスワードのハッシュ化も PasswordEncoder を登録・変更処理に組み込むだけで済みます。自作すると漏れやすい部分ほど既製の実装があります。

一方、ユーザー登録、パスワード再設定、多要素認証の登録画面、退会といったID管理の業務フローは、Spring Securityが用意するのは部品までで、画面と手順は自分で作る範囲です。社内外の複数システムで同じアカウントを使うなら、Keycloakや Microsoft Entra ID などのIDプロバイダーにID管理を任せ、Spring Security側はOpenID Connectのログインやトークン検証(リソースサーバー)に絞る構成の方が保守の負担が小さくなります。トークンの検証方式はJWTとは?構造・署名検証の仕組みとセッション・OAuth/OIDCとの違い、ヘッダーの書き方はBearer Token(ベアラートークン)とは?で解説しています。認証基盤を含めた設計から相談したい場合は、一爽の認証基盤・ID管理システム開発で対応しています。

よくある質問

Spring BootとSpring Securityの違いは何ですか?

Spring Bootはアプリの起動と設定を自動化する仕組みで、セキュリティ機能そのものは持っていません。Spring Securityが認証・認可を実装し、Spring Bootはそれを既定の設定(全URL認証必須・生成パスワードのユーザー)で組み込みます。

Spring Securityの最新バージョンはいくつですか?

2026年10月18日時点の最新安定版は7.1.1(Spring Boot 4.1.1が採用)です。7.2.0は開発版(M2)で、Springのサポート表では7.2系の初回リリースが2026年11月とされています。

CSRF対策は無効にしてよいですか?

ブラウザから使われる画面やAPIでは無効にしないでください。公式ドキュメントは、ブラウザ以外のクライアントだけが使うサービスなら無効化してよいとしています。「Invalid CSRF token」などのエラーの直し方はInvalid CSRF tokenの意味と直し方を参照してください。

CORSの設定はどこに書きますか?

SecurityFilterChainで http.cors(Customizer.withDefaults()) を有効にし、CorsConfigurationSource のBeanで許可するオリジンを定義します。プリフライト要求にはCookieが付かないため、Spring Securityより前にCORSを処理しないと認証エラーで弾かれます。ReactなどのSPAと組み合わせる手順はSpring BootとReactの連携方法で実測しています。

SecurityFilterChainは何本まで定義できますか?

本数の上限はなく、securityMatcher で対象URLを分けて複数定義できます。先に一致したチェーンだけが使われるので、@Order で狭い範囲のチェーンを先に置きます。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.23 テックブログ Renta!不正アクセスでサービス停止:再開未定の現状と運営側の停止判断・証拠保全・段階的再開
  2. 2026.07.09 テックブログ Muse Imageとは?Metaの画像生成AIの使い方・API料金(1枚0.01ドル)と日本での提供状況【2026年10月】
  3. 2026.10.22 テックブログ Tomcatのバージョン一覧とサポート期限【2026年10月】最新版11.0.27、9.0系は2027年3月末終了・9.1系は2030年末まで
  4. 2026.10.23 テックブログ Splunk 脆弱性CVE-2026-76299:影響版の確認と10.2.8などへの更新手順
  5. 2026.10.24 テックブログ ブラストメール不正アクセス:配信先288件の漏えいと利用企業の報告・通知の手順

RELATED POSTS 関連記事

目次