セッション固定攻撃(Session Fixation)を「過去の遺物」にする:現場で通用する防御の鉄則
現場でインシデント対応をしていると、いまだに「セッション管理はフレームワーク任せだから大丈夫」と油断しているエンジニアに出会うことがある。だが、フレームワークのデフォルト設定を理解せず、セッションのライフサイクルを制御していないアプリは、脆弱性を「隠し持っている」のと同じだ。
今日は、攻撃者がいとも簡単にセッションをハイジャックする「セッション固定攻撃」について、その泥臭い手口と、今日から即座に適用できる実装の極意を伝授しよう。
—
1. 攻撃の構図:なぜ「ログイン前」が狙われるのか
セッション固定攻撃の恐ろしさは、攻撃者が「自分の知っているセッションID」を被害者に押し付け、そのIDをログインによって「有効化」させる点にある。
1. 罠の設置: 攻撃者が自身のブラウザで対象サイトにアクセスし、サーバーから発行された有効なセッションID(例: SID=123)を取得する。
2. IDの注入: 攻撃者は「https://example.com/?SID=123」のようなURLを細工し、ターゲットに踏ませる(あるいはクロスドメインの脆弱性を突き、Cookieを強制セットする)。
3. ログイン: ターゲットがそのリンク経由でログインすると、サーバーは「SID=123 は有効なまま」で認証状態に遷移させてしまう。
4. 乗っ取り: 攻撃者は自分のブラウザで SID=123 をセットしたままリロードする。すると、ターゲットの権限でログイン済みの画面が目の前に現れる。
これは技術的なバグというより、「認証前後でセッションIDを使い回す」という設計上の甘さを突いた典型的な攻撃だ。
—
2. 実装の鉄則:ログイン時に「セッションIDを殺す」
防御の鍵はただ一つ。「ログイン成功の直後に、現在のセッションを破棄し、新しいIDを発行すること」。これに尽きる。
PHPでのセッション再生成(実務コード)
PHPの場合、session_regenerate_id(true) を呼び出すのが黄金律だ。true を指定することで、古いセッションデータがサーバーから確実に削除される。
Python (FastAPI/Flask) でのヒント
フレームワークを使う場合も同様だ。FastAPIであれば、ログイン成功時に現在のセッションクッキーをクリアし、新しいクッキーをレスポンスヘッダーで発行する設計にする。
FastAPIでのセッション再生成の概念
from fastapi import Response
@app.post(“/login”)
async def login(response: Response, user: User):
# …認証ロジック…
# ログイン成功時
# 新しいセッションIDを生成し、Cookieを上書き設定する
new_session_id = generate_secure_token()
response.set_cookie(
key=”session_id”,
value=new_session_id,
httponly=True, # JSからのアクセスを禁止
secure=True, # HTTPS必須
samesite=”Lax” # CSRF対策も忘れずに
)
return {“message”: “Logged in”}
—
3. インフラ・設定で畳み掛ける(防御の多層化)
コードレベルの対策に加え、Webサーバーやブラウザの機能で「逃げ道」を塞ぐのが、プロのインフラエンジニアの仕事だ。
Nginx/App構成でのヘッダー設定
セッションIDが漏洩しても悪用されないよう、Cookie属性を厳格に管理する。
Nginxの設定例:Cookieの漏洩防止
すべてのSet-Cookieヘッダーに対して属性を付与する設定が望ましい
proxy_cookie_path / “/; HTTPOnly; Secure; SameSite=Lax”;
- HttpOnly: JavaScriptから
document.cookieでセッションIDを盗まれないようにする。XSS対策としても必須。 - Secure: 暗号化された通信(HTTPS)以外ではセッションIDを送信させない。
- SameSite=Lax/Strict: 外部からのリクエストでセッションIDが送信されるのを防ぐ。
—
4. 最後に:現場で「これだけは守れ」
セキュリティ対策において、最も危険なのは「一度実装したから大丈夫」という慢心だ。以下のチェックリストをチームのPR(プルリクエスト)の指針に加えてほしい。
1. ログイン成功時、確実にIDが変わっているか?(Burp Suite等のプロキシツールでログイン前後のIDを比較確認せよ)
2. ログアウト時にはセッションを完全に破棄しているか?(session_destroy() を呼ぶだけで満足せず、クッキーの生存期間をマイナスにするのがベストだ)
3. セッションのタイムアウト時間は適切か?(放置された端末からの乗っ取りを防ぐため、長時間操作がないセッションは自動破棄する設計になっているか)
セッション固定攻撃は、古典的だが「ログイン」という最も重要な境界線を狙う攻撃だ。ここを完璧に守ることは、ユーザーの信頼を守ることと同義である。
さあ、今すぐコードベースを確認し、ログイン処理の中に session_regenerate_id が存在するかチェックしてほしい。もし無ければ、それが今日君が修正すべき最優先のタスクだ。
コメント