【実務・中級編】 セッション固定攻撃(Session Fixation)のメカニズムと防御 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

セッション固定攻撃:なぜ「ログイン前後」のID再生成がシステムの生死を分けるのか

現場で長年インシデント対応をしていると、「認証は通っているのに、なぜか権限昇格が起きている」という不可解な事案に遭遇することがあります。その黒幕の正体の一つが「セッション固定攻撃(Session Fixation)」です。

多くのエンジニアが「セッション管理はフレームワークがやってくれるから大丈夫」と高を括っていますが、フレームワークは「再生成のタイミング」までは制御してくれません。 ここでは、教科書的な説明は抜きにして、攻撃者がどうやって獲物を仕留めるのか、そして我々エンジニアがどうコードで防ぐべきか、泥臭い実務の視点から解説します。

—

1. 攻撃者が狙う「隙間」:PoCのメカニズム

セッション固定攻撃の目的はシンプルです。「攻撃者が用意したセッションIDを、被害者に使わせる」こと。

攻撃の流れはこうです。

1. 餌の設置: 攻撃者は攻撃対象のWebサイトにアクセスし、有効なセッションID(例: SESSID=evil12345)を取得します。
2. 罠の配布: 攻撃者は被害者に「ログインしてね」とURLを送ります(例: https://bank.example.com/?SESSID=evil12345)。もしURLパラメータでセッションIDを受け入れる仕様なら、被害者のブラウザにそのIDがセットされます。
3. ログイン待機: 被害者がそのIDを持ったままログインします。
4. 乗っ取り: サーバー側でセッションIDが再生成されなければ、サーバーは「evil12345=認証済みユーザー」と認識します。攻撃者は自分のブラウザで同じIDを使ってアクセスし、被害者のアカウントに入り込みます。

重要な盲点: 多くの開発者が「Cookieさえ盗まれなければ安全」と考えがちですが、「Cookieを盗む必要はない、最初から自分のを知っていればいい」というのがこの攻撃の恐ろしいところです。

—

2. 鉄則:ログイン時に「セッションを捨てて作り直す」

防御の基本は、「認証状態が変わる瞬間に、セッションIDを確実に破棄して再発行する」こと。これに尽きます。

PHPによる実装例

PHPでは session_regenerate_id(true) を呼ぶのが定石です。true を指定することで、古いセッションファイルを削除し、新しいIDに切り替えます。

<?php
// ログイン処理の直後、必ずこの関数を呼ぶ
function login_success_handler($user_id) {
    // 1. 古いセッションを破棄し、新しいIDを発行する
    // trueを指定することで、旧セッションファイルをサーバーから削除する
    session_regenerate_id(true);

    // 2. 認証セッションをセット
    $_SESSION['user_id'] = $user_id;
    $_SESSION['authenticated'] = true;
}
?>

—

3. Cookie属性を「武装」させる

セッションIDを再生成しても、Cookieの設定が甘ければ XSS などで簡単に盗まれます。以下の3つの属性は、設定ではなく「必須の守備隊」と考えてください。

php.ini での推奨設定

; HttpOnly: JavaScriptからのアクセスを禁止(XSS対策)
session.cookie_httponly = 1

; Secure: HTTPS経由でしかCookieを送信しない(盗聴対策)
session.cookie_secure = 1

; SameSite: CSRF対策。厳格にするならStrict、利便性重視でもLaxを明示
session.cookie_samesite = "Lax"

Nginxでヘッダーを強制上書きする場合

もしPHP側での制御が不安なら、Webサーバー側で強制的にヘッダーを付与するのも賢い戦略です。

# nginx.conf の server または location ブロック
add_header Set-Cookie "Path=/; HttpOnly; Secure; SameSite=Lax";

—

4. 現場の教訓:なぜ「フレームワーク依存」が危険なのか

よくある失敗は、ログイン用のAPIを独自に作ったり、古いコードベースをそのまま使い続けたりすることです。特に「URLパラメータでセッションIDを受け入れる仕様(PHPSESSID=xxxをURLに含める)」が有効になっていると、上記の防御コードを書いても意味がありません。

チェックリスト:

  • php.ini の session.use_trans_sid が 0 になっているか?(URLにIDを埋め込む機能を無効化)
  • session.use_only_cookies が 1 になっているか?(Cookie以外でIDを受け付けない)
  • ログイン時に session_regenerate_id(true) を呼び忘れていないか?

—

最後に:セキュリティは「性悪説」で設計する

我々が守るべきは「信頼できるユーザー」ではなく、「常に攻撃手法をアップデートしている攻撃者」です。

「とりあえず動く」コードを書くのはジュニアエンジニアの仕事です。シニアエンジニアは、「セッションが奪われたらどうなるか? 認証が突破されたらどうなるか?」という最悪のシナリオを想像し、そのプロセスを遮断するコードを書きます。

セッション固定攻撃は、ログイン処理のわずか1行の記述漏れから始まります。今日からすぐに、自社コードのログインハンドラを確認してください。「再生成」というたった一つのアクションが、数百万件の個人情報流出を未然に防ぐ防波堤になるのです。

コメント

タイトルとURLをコピーしました