セッション固定攻撃対策の設定を完全解説!初心者でもわかるSpringセキュリティの基本
新人
「ログイン処理ができるようになったんですが、『セッション固定攻撃』っていう言葉を見かけました。これはなんですか?」
先輩
「セッション固定攻撃とは、攻撃者があらかじめセッションIDを固定して、ログイン後もそのIDが使われるようにしてしまう攻撃のことなんだ。」
新人
「それって、ログインされたあとにそのセッションIDを使って不正アクセスできるってことですか?」
先輩
「そのとおり!だからこそセッション固定攻撃とは何かを理解して、対策することが重要なんだよ。では詳しく説明していこうか。」
1. セッション固定攻撃とは?(基本的な説明と仕組み)
セッション固定攻撃とは、ログイン前に決められたセッションIDを、ログイン後もそのまま使わせることで、攻撃者がユーザーになりすますことを目的とした攻撃です。これはWebアプリケーションにおける深刻なセキュリティリスクの一つです。
この攻撃の仕組みは非常にシンプルです。まず攻撃者がターゲットユーザーに対して、自分で生成したセッションIDを何らかの方法で使わせます。例えば、メールやURLのパラメータに埋め込んで送るなどの手段が考えられます。
その後、ユーザーがそのセッションIDでログインすると、セッションIDが変わらない限り、攻撃者は同じIDを使ってログイン後の情報にアクセスできてしまいます。これがSpring セッションセキュリティにおける脅威となります。
図で表すと以下のような流れです。
- ① 攻撃者がセッションIDを生成
- ② ユーザーにそのIDを使わせる
- ③ ユーザーがログイン
- ④ 攻撃者がそのIDで不正にアクセス
このような問題を防ぐには、ログイン成功時にセッションIDを必ず再生成する設定が必要になります。それがSpring セッション固定対策の基本となるのです。
2. なぜセッション固定攻撃が危険なのか
セッション固定攻撃が危険な理由は、ユーザーが気づかないうちにログイン状態を乗っ取られるという点にあります。セッションIDは、Webアプリケーションにおいて「誰がアクセスしているか」を識別する非常に重要な情報です。
このIDが第三者に知られた状態でログインされてしまうと、そのセッションが有効な限り、攻撃者は自由にそのアカウントにアクセスできる状態になります。たとえパスワードが漏れていなくても、セッションIDだけで認証済みの状態を再現できるのです。
特に、セッションIDをURLのパラメータとして扱っているような古いシステムでは、この攻撃が成立しやすくなります。以下は、脆弱な例です。
<a href="http://example.com/login?jsessionid=ABC123">ログイン</a>
このようなリンクがメールやチャットで送られ、ユーザーがうっかりクリックすると、そのjsessionidが固定されてしまい、攻撃者にとっては格好の標的になります。
実際に、この脆弱性が利用された事件も多数報告されており、特にセキュリティ意識の低いシステムや、ログイン処理に自作のセッション管理を行っている場合に発生しやすいです。
そのため、Spring セッションセキュリティを適切に構成し、ログイン時に必ずセッションIDを再生成するような設定が必要です。これがセッション固定攻撃とは何かを理解した上での最初の対策となります。
3. Spring Securityにおけるセッション固定攻撃対策の仕組み
Spring Security セッション固定対策では、ログイン成功時にセッションIDを再生成することで、セッション固定攻撃を防ぎます。これはSpring Securityが自動的に実施するセキュリティ対策のひとつです。
Spring Securityは、標準で「Session Fixation Protection」が有効になっており、ログイン処理が完了すると、旧セッションを無効にし、新しいセッションを生成してくれます。
この仕組みにより、ログイン前に使っていたセッションIDが、ログイン後には無効となり、攻撃者が同じセッションIDを使ってアクセスすることができなくなります。
実際には、sessionManagement()にあるsessionFixation()の設定によって制御されます。設定例は次のとおりです。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.sessionManagement(session -> session
.sessionFixation().migrateSession()
);
return http.build();
}
migrateSession()が指定されていると、ログイン成功後にセッションIDが再生成され、元のセッション情報(属性など)は引き継がれます。これがSpring Securityにおけるセッション固定対策の基本動作です。
4. セッションIDの再生成(Session Fixation Protection)の実装方法
セッションID 再生成の具体的な設定は、Spring SecurityのHttpSecurity設定内に含めます。以下は、その詳細な実装例です。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home", true)
.permitAll()
)
.sessionManagement(session -> session
.sessionFixation().migrateSession()
);
return http.build();
}
sessionFixation().migrateSession()はセッションIDを新しく生成しつつ、ログイン前のセッション属性(例:カート情報など)を引き継ぎます。なお、以下のようなモードもあります:
none():セッションIDを再生成しない(非推奨)newSession():新しいセッションを作成し、前の情報を破棄changeSessionId():セッションIDのみ変更(Servlet 3.1以降)migrateSession():セッションID変更+属性引き継ぎ(推奨)
セッション固定攻撃対策として最もよく使われるのがmigrateSession()です。これにより、ユーザー体験を損なわずにセキュリティを確保できます。
5. セッション管理設定の基本(sessionManagement設定の使い方)
Spring セッション管理設定は、sessionManagement()ブロック内でまとめて行うことができます。ここではセッションの最大数や無効時の動作、同時ログイン数の制御なども設定可能です。
たとえば、同じユーザーが複数の端末でログインすることを防止する設定は以下のように記述します。
.sessionManagement(session -> session
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
)
この設定では、maximumSessions(1)により同時に1セッションだけ許可し、maxSessionsPreventsLogin(true)により2回目のログインをブロックします。
セッションの無効時にリダイレクトしたい場合は、次のように設定します。
.sessionManagement(session -> session
.invalidSessionUrl("/login?invalid")
)
また、ログアウト時にセッションを完全に破棄したい場合も、logout()で明示的に指定できます。
.logout(logout -> logout
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.logoutSuccessUrl("/login?logout")
)
Spring セッション固定対策をきちんと行うには、これらのセッション管理の設定と一緒に活用することが重要です。セッションID再生成に加えて、セッション数の制限や無効化処理もセキュリティ強化の一環として必須です。
6. セッション固定攻撃対策の落とし穴とよくある設定ミス
セッション固定攻撃 対策方法としてSpring SecurityのsessionFixation()設定は有効ですが、開発現場では設定ミスによるセキュリティホールが多く見られます。ここでは、代表的な落とし穴を紹介します。
まずありがちなミスは、sessionFixation().none()を指定してしまうことです。これは「セッションIDを変更しない」設定となり、セッション固定攻撃に対して無防備な状態になります。たとえば、以下のようなコードはNGです。
.sessionManagement(session -> session
.sessionFixation().none()
)
このような設定をしてしまうと、ログイン前と後でセッションIDが同一になり、攻撃者がIDを固定できてしまいます。セッション固定攻撃対策として、必ずmigrateSession()やchangeSessionId()を使うべきです。
また、ログインフォームを独自に作成してSpring Securityの仕組みをバイパスしてしまうケースも注意が必要です。formLogin()の設定を無視して自前の認証処理を組むと、セッションIDの再生成処理が実行されない可能性があります。
セキュリティを破らないためには、できるだけHttpSecurityの構成を活かして、公式が提供するログイン・ログアウト機能を活用することが推奨されます。
7. 実際の攻撃を想定したセッション管理例
ここでは、セッション固定攻撃 対策方法を実装したうえで、実際の攻撃を想定したシナリオを使って、どのように保護できるのかを確認します。
想定シナリオ:
- 攻撃者がセッションID
ABC123を含むログインURLを生成 - そのURLをユーザーに送信
- ユーザーがログインページへアクセスし、そのIDで認証
- Spring SecurityがセッションIDを再生成
- 攻撃者が
ABC123でアクセスしても認証されない
このような流れを実装するためのSpring Security設定例は以下のとおりです。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.sessionManagement(session -> session
.sessionFixation().migrateSession()
.maximumSessions(1)
.maxSessionsPreventsLogin(false)
)
.logout(logout -> logout
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
);
return http.build();
}
この構成では、ログイン成功時にセッションIDを変更し、同時ログインを1つに制限しています。さらに、ログアウト時にはクッキーのJSESSIONIDも破棄することで、より確実なセキュリティが保てます。
Spring セッション管理 設計をしっかり行えば、実際の攻撃に対しても安全性を保つことができます。
8. セッション固定攻撃を防ぐために設計時に気をつけるポイント
Spring セッション管理 設計において、セッション固定攻撃を未然に防ぐためには、単なる設定だけでなく、アプリケーション設計時点での配慮も重要です。
まず最も重要なのは、セッションIDをURLに含めないことです。URLにセッションIDを含めると、それがログや履歴、外部リンクに残ってしまうリスクがあります。可能な限りクッキーのみでセッションIDを管理し、jsessionidがURLに出ないよう設定すべきです。
次に、セッションタイムアウトの設計です。ユーザーが一定時間操作を行わなかった場合には、セッションを自動的に切断することで、攻撃者に利用されるチャンスを減らせます。以下は、セッションの有効期限を設定する方法です。
@Configuration
public class SessionConfig {
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addContextCustomizers(context -> context.setSessionTimeout(15)); // 単位は分
return factory;
}
}
また、アプリケーション全体のセッション方針をドキュメント化し、チーム全体で共有することも大切です。特に複数人で開発を行う現場では、セッション周りの共通ルールが無いと、部分的に脆弱な実装になりかねません。
最後に、セッションIDが漏洩した場合に備えて、アクセスログや監査ログの整備も設計段階で組み込むべきです。不正ログインや同時アクセスの検出ができるようにしておくと、万が一のときにも素早く対応できます。
これらを意識して設計することで、セッション固定攻撃を実行段階で防止できるだけでなく、運用中のセキュリティを高いレベルで維持できます。