セッション固定攻撃とは
セッション固定攻撃は、攻撃者が知っているセッションIDを被害者に使わせ、そのままログインさせる攻撃です。
対策の中心は、ログイン成功時にセッションIDを必ず再発行し、ログイン前のIDをログイン後へ持ち越さないことです。
セッションIDを盗む攻撃とは少し違います。すでに知っているIDを、被害者のログイン済みセッションに育ててしまう点が特徴です。
攻撃の流れ
危険な実装では、ログイン前の匿名セッションIDを、ログイン後もそのまま使います。
1. 攻撃者がサイトにアクセスして session_id=attack123 を得る
2. 攻撃者が被害者に attack123 を使わせる
3. 被害者がその状態でログインする
4. サーバーが attack123 をログイン済みセッションにする
5. 攻撃者も attack123 を持っているため、被害者としてアクセスできる
問題は、ログイン成功後もセッションIDが変わらないことです。
ログイン前: session_id=attack123
ログイン後: session_id=attack123
安全な実装では、ログイン成功時にIDを変えます。
ログイン前: session_id=attack123
ログイン後: session_id=new_random_789
古い attack123 は無効化します。
セッションハイジャックとの違い
似た言葉にセッションハイジャックがあります。
| 攻撃 | 何が起きるか |
|---|---|
| セッション固定 | 攻撃者が知っているIDを被害者に使わせる |
| セッションハイジャック | 被害者の有効なIDを盗む |
| XSSによるCookie窃取 | JavaScriptなどでCookieを盗む |
| CSRF | 被害者のCookie自動送信を利用して操作させる |
セッション固定は「盗む」より前に、「攻撃者が知っているIDでログインさせる」攻撃です。そのため、ログイン時のID再発行が非常に重要になります。
どうやって固定されるのか
現代のブラウザでは、他サイトから任意のCookieを自由に設定できるわけではありません。それでも、設計や構成によってリスクが残ります。
代表的な入口:
- URLにセッションIDを入れる実装
- サブドメインから広いDomainのCookieをセットできる構成
- HTTP通信が残っていてCookieを差し替えられる構成
- 脆弱な画面でレスポンスヘッダーを注入される
- 古いアプリがログイン前セッションをログイン後へ再利用する
特に、URLにセッションIDを入れる実装は避けます。
避けたい例:
https://example.com/login?session_id=attack123
URLは履歴、Referer、ログ、チャット、スクリーンショットに残りやすいため、認証用の秘密値を入れる場所ではありません。
ログイン時に再発行する
最重要対策は、ログイン成功時のセッション再発行です。
before login:
session_id=old_anonymous
after login:
invalidate old_anonymous
create new_authenticated
Set-Cookie: session_id=new_authenticated
実装上のポイント:
- 認証成功後に新しいセッションIDを発行する
- 古いセッションIDを無効化する
- 必要な匿名データだけ移行する
- CSRFトークンも再発行する
- 権限昇格時にも再発行する
ショッピングカートや一時設定など、ログイン前の匿名セッションに情報がある場合は、必要なデータだけ新セッションへコピーします。古いセッションをログイン済みに昇格させないことが大切です。
権限昇格時にも再発行する
ログイン時だけでなく、認証レベルが上がる場面でもセッション更新を検討します。
例:
- 一般ユーザーから管理者画面へ入る
- 2要素認証を通過する
- パスワード変更画面へ入る
- 決済や住所変更など重要操作を行う
- 保護者アカウントから受講生情報へアクセスする
このような場面では、現在のセッションが本当にその操作に使ってよい状態かを確認します。必要に応じて再認証やセッションID再発行を行います。
Cookieのスコープを狭くする
セッション固定対策では、Cookieの送信範囲も重要です。
まず、不要な Domain を付けないhost-only Cookieを検討します。
Set-Cookie: session_id=...; Path=/; HttpOnly; Secure; SameSite=Lax
Domain=example.com を付けると、サブドメインへ送信範囲が広がります。
Set-Cookie: session_id=...; Domain=example.com; Path=/; HttpOnly; Secure; SameSite=Lax
サブドメインをすべて同じ安全水準で管理できていない場合、認証Cookieを広いDomainにするのは避けます。
__Host- Prefixを使う
対応ブラウザでは、Cookie名に __Host- Prefixを使うことで、より安全な条件をブラウザに強制できます。
Set-Cookie: __Host-session_id=abc; Path=/; Secure; HttpOnly; SameSite=Lax
__Host- Cookieでは、一般に次の条件が求められます。
Secureが必要Domainを指定できないPath=/が必要
これにより、サブドメインから広いDomain Cookieを上書きするような事故を減らしやすくなります。
すべての問題を解決する魔法ではありませんが、ログインセッションCookieでは有力な選択肢です。
HttpOnlyは固定攻撃の直接対策ではない
HttpOnly は重要ですが、役割を正しく理解します。
Set-Cookie: session_id=abc; HttpOnly
HttpOnly は、JavaScriptからCookieを読みにくくする属性です。XSSによるCookie窃取リスクを下げます。
ただし、セッション固定攻撃の中心対策は HttpOnly ではありません。攻撃者が知っているIDをログイン後へ持ち越さないこと、つまりログイン時のセッションID再発行が本体です。
SameSiteも万能ではない
SameSite=Lax や Strict は、CSRF対策として有効です。
しかし、セッション固定の全パターンを防ぐものではありません。特に同一site内のサブドメイン問題、古い実装、URLセッションIDのような設計ミスは、SameSiteだけでは防げません。
セッション固定対策は、次を組み合わせます。
- ログイン時のセッションID再発行
- 古いセッションIDの無効化
- URLにセッションIDを入れない
- Cookieスコープを狭くする
Secure/HttpOnly/SameSiteを設定する- 可能なら
__Host-Prefixを使う
検知とログ
完全な防御だけでなく、怪しい挙動を見つける設計も有効です。
見るとよいもの:
- ログイン直前と直後でセッションIDが変わっているか
- 同じセッションIDが複数IPや複数User-Agentで使われていないか
- ログイン後すぐに遠い地域からアクセスされていないか
- 管理者権限への昇格時にID再発行されているか
- URLやログにセッションIDが出ていないか
ただし、IPやUser-Agentの固定は慎重に扱います。モバイル回線、VPN、企業ネットワークでは値が変わることがあります。厳密に縛りすぎると、正規ユーザーを落とす原因になります。
ログにセッションIDそのものを残すのも避けます。必要ならハッシュ化した識別子で追跡します。
テスト観点
セッション固定対策は、テストで確認できます。
確認すること:
- ログイン前後でセッションIDが変わる
- ログイン前のセッションIDではログイン後ページに入れない
- ログイン後、古いセッションIDがストアから削除される
- 2要素認証後や管理画面遷移時に必要ならIDが変わる
- URLにセッションIDを受け付けない
- 同名CookieがDomain/Path違いで残らない
__Host-を使う場合、Domainなし、Path=/、Secureになっている
特に「ログイン前のCookieを記録しておき、ログイン後にその古いCookieだけでアクセスできないか」を確認すると、固定攻撃への耐性を見やすいです。
まとめ
セッション固定攻撃は、攻撃者が知っているセッションIDを被害者に使わせ、ログイン後も同じIDを使わせる攻撃です。
- ログイン成功時にセッションIDを再発行する
- 古い匿名セッションIDを無効化する
- URLにセッションIDを入れない
- CookieのDomainを不要に広げない
Secure/HttpOnly/SameSiteを設定する- 可能なら
__Host-Prefixを使う - 権限昇格時にも再発行を検討する
「ログイン前のIDをログイン後へ持ち越さない」。これがセッション固定対策の核です。