【入門編】 セッション固定化攻撃(Session Fixation)の仕組みと対策 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!Webアプリケーションの開発やインフラの管理、本当にお疲れ様です。
新しい技術を覚えるのって、覚えることがたくさんあって大変ですよね。「セキュリティ対策って難しそう…」と感じている方も多いのではないでしょうか。

今回は、Webアプリの脆弱性の一つである「セッション固定化攻撃(Session Fixation)」について、専門用語をできるだけ使わず、身近な「合鍵」の例えを交えながら、一歩ずつ優しく紐解いていきたいと思います。

実務ですぐに使える対策コードも用意しましたので、一緒にマスターしていきましょう!

—

1. セッションってなぁに?(基本のおさらい)

まず、Webサイトにおける「セッション」について簡単におさらいしておきましょう。

私たちが普段、ネットショッピングやSNSにログインするとき、IDとパスワードを入力しますよね。でも、ページを移動するたびに「あなたは誰ですか?」とパスワードを聞かれたら、面倒くさくて仕方がありません。

そこで登場するのがセッションIDです。
サーバーは、あなたがログインしたときに「この人はこういう人です」という証明書(セッションID)を発行し、あなたのブラウザに預けます。ページを移動するときにブラウザがその証明書をそっとサーバーに見せることで、「あ、〇〇さんですね、いってらっしゃい!」とスムーズにやり取りができるようになっているんです。

この証明書は、一般的に PHPSESSID などのクッキー(Cookie)という仕組みを使ってブラウザに保存されます。

—

2. セッション固定化攻撃の仕組みを「合鍵」で例えてみよう

では、本題の「セッション固定化攻撃」とは一体どんなものなのでしょうか?
少し物騒ですが、マンションのオートロックと鍵の仕組みに例えて考えてみましょう。

巧妙な手口の流れ

1. 攻撃者の準備
攻撃者は、とあるショッピングサイトにアクセスし、自分が使うための「新しい鍵(セッションID)」をあらかじめ手に入れます。
2. ターゲットへの罠(鍵の押し付け)
攻撃者は、その「自分が持っている鍵」を、ターゲットであるあなたに使わせようと企みます。例えば、罠のURL(https://example.com/?PHPSESSID=attacker_12345 のような形)を踏ませたりして、あなたのブラウザにそのセッションIDを強制的にセットさせます。
3. あなたがログイン
あなたは何も知らずにそのサイトを開き、自分のIDとパスワードでログインします。
4. 乗っ取り完了!
ここが最大のポイントです。「ログインしたのに、サーバーがセッションIDを新しく作り直してくれなかった場合」、サーバーは「おっ、さっきの attacker_12345 の人がログインしたんだな!」と認識してしまいます。

結果どうなるか?
攻撃者は、あなたがログインする前に仕込んだ「同じ鍵」を自分の手元に持っています。あなたがログインした瞬間、攻撃者もあなたと同じ権限で、あなたのマイページにスイスイと入れてしまうのです。これがセッション固定化攻撃の恐ろしい仕組みです。

—

3. なぜこの攻撃が成立してしまうのか?

最大の原因は、「ユーザーがログインする前後で、セッションIDを新しく貼り替えて(再生成して)いないこと」にあります。

先ほどのマンションの例で言えば、エントランスを通る前(ログイン前)に他人が用意した合鍵を渡され、そのまま自分の部屋の鍵として登録してしまったような状態です。
「ログインという重要なイベントが起きたんだから、身分証明書(セッションID)も新しく発行し直せばいいじゃない!」というのが、セキュリティの基本思想になります。

—

4. 【実務向け】今日からできる確実な防御策

それでは、私たちが開発するWebアプリをこの攻撃から守るためにはどうすればよいのでしょうか?
答えはシンプルです。「ログイン成功時に、必ずセッションIDを新しく作り直す(リジェネレイトする)」これだけです。

PHPを例に、具体的なコードを見てみましょう。

良い例:ログイン成功時にセッションIDを再生成するPHPコード

<?php
// セッションを開始します
session_start();

// ユーザーからの入力を受け取り、データベース等で認証を行ったと仮定します
$is_authenticated = true; // 認証成功のフラグ

if ($is_authenticated) {
    // 【最重要ポイント】
    // セッション固定化攻撃を防ぐため、ログイン成功直後にセッションIDを完全に新しく作り直します。
    // true を指定することで、古いセッションファイルもサーバー側から綺麗に削除されます。
    session_regenerate_id(true);

    // ユーザー情報をセッションに保存します
    $_SESSION['user_id'] = 12345;
    $_SESSION['username'] = 'yamada_taro';

    echo "ログインに成功しました!セッションIDは安全に再発行されました。";
} else {
    echo "ログインに失敗しました。";
}
?>

コードのポイント解説

  • session_regenerate_id(true); という一行が、すべての防衛の要になります。
  • 引数に true を渡すことで、攻撃者が仕掛けた古いセッションIDを無効化し、全く新しい別のIDへと切り替えてくれます。これを行っておけば、万が一ログイン前にセッションIDを固定されようとも、ログインした瞬間にそのIDが無効になるため、攻撃者は中に入ることができなくなります。

—

5. さらに万全を期すためのインフラ・設定のポイント

PHPのコードでの対策に加えて、Webサーバーやクッキーの設定を見直すことも非常に重要です。

1. Cookieの HttpOnly 属性を有効にする
セッションIDが保存されているクッキーに HttpOnly 属性を付与することで、万が一サイトにクロスサイトスクリプティング(XSS)などの別の脆弱性があった場合でも、JavaScriptからセッションIDを盗み出されるリスクを防ぐことができます。
2. Cookieの Secure 属性を有効にする
通信を必ず暗号化(HTTPS)し、セッションIDが平文で盗聴されるのを防ぎます。

PHPの設定ファイル(php.ini)では、デフォルトで以下のように安全な設定にしておくのが現代のWeb開発のスタンダードです。

; JavaScriptからクッキーへのアクセスを禁止する(XSS対策)
session.cookie_httponly = 1

; HTTPS接続時のみクッキーを送信する(盗聴対策)
session.cookie_secure = 1

; URLパラメータ経由でのセッションIDの伝播を禁止する(セッション固定化の温床を防ぐ)
session.use_only_cookies = 1

—

おわりに

セッション固定化攻撃の仕組みと、その対策についてイメージは湧きましたでしょうか?

難しく感じるセキュリティ対策も、「泥棒に合鍵を使わせないために、ログインしたら鍵を新しく作り直す」という現実世界の防犯意識に置き換えてみると、すごくスッキリ腑に落ちるはずです。

新人のIT担当者や開発者の皆さんが、日々のコーディングの中で「おっ、ここでちゃんとセッションIDの再生成をしているか確認しよう!」と意識するきっかけになれば、これほど嬉しいことはありません。
一歩ずつ、安全で堅牢なWebアプリケーションを作っていきましょう!

コメント

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