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

こんにちは!Webアプリケーション開発やセキュリティ対策の現場へようこそ。
新人のIT担当者や、これからセキュリティの勉強を始める開発者のみなさん、日々覚えることがたくさんあって大変ですよね。でも、大丈夫です!一歩ずつ、身近な例えから確実に学んでいきましょう。

今回は、Webサイトのセキュリティにおいて非常に重要なテーマである「セッション固定攻撃(Session Fixation)」と、その泥棒を防ぐための「セッションIDの再生成」、そして「Cookieの頑丈な鍵(属性設定)」について、徹底的に噛み砕いて解説していきます。

実務でそのままコピーして使える設定サンプルも用意したので、ぜひ最後まで読んで自分のものにしてくださいね!

—

1. 「セッション固定攻撃」ってなに? —— 家の鍵に例えてみよう

まずは、攻撃のメカニズムをイメージしてみましょう。Webサイトにおける「セッション」とは、あなたがログインしてからログアウトするまでの「お店の会員証」や「テーマパークのフリーパス」のようなものです。

もし、泥棒が次のような悪だくみをしたらどうなるでしょうか?

1. 先回りの罠: 泥棒(攻撃者)が、とあるショッピングサイトにアクセスし、自分用の「番号付きのフリーパス(セッションID)」をあらかじめ手に入れます。
2. 鍵のすり替え: 泥棒は、あなた(被害者)にメールなどで「このURLからログインしてお得なクーポンをゲットしてね!」と、自分が手に入れたフリーパスの番号(セッションID)が仕込まれた特別なリンクを踏ませます。
3. 無防備なログイン: あなたはその罠に気づかず、そのリンクからサイトにアクセスし、自分のIDとパスワードを入力して無事にログインしました。
4. 侵入成功: ここが最大のポイントです!あなたは「自分のアカウント」でログインしたつもりですが、お店があなたに渡したフリーパスの番号は、最初に泥棒が用意したもの(固定されたもの)です。

結果として、泥棒はあなたが使っているのと同じ「フリーパスの番号」を握りしめているため、あなたになりすまして自由にお買い物や個人情報の閲覧ができてしまうのです。これがセッション固定攻撃の恐ろしい仕組みです。

—

2. 泥棒をシャットアウトする最強の対策:ログイン前後の「セッション再生成」

この攻撃を防ぐための鉄則は、ずばり「ログインが成功した瞬間、フリーパスの番号(セッションID)を新しく発行し直すこと」です。これをセッションの再生成と呼びます。

現実の世界で例えるなら、お店の入り口(ログイン前)にもらった仮の番号札を、会員登録(ログイン)を完了した瞬間に、「おめでとうございます!こちら、あなた専用の新しいゴールド会員番号です!」と、古い番号を無効化して、全く新しい番号のパスに切り替えるイメージです。

もし攻撃者が古い番号を握りしめて待っていたとしても、あなたがログインした瞬間にその番号はゴミ箱行きになり、新しい別の番号に切り替わるため、泥棒は中に入ることができなくなります。

実装コード例(PHPでのセッション再生成)

それでは、実際の開発現場でどのように実装するのか、PHPを例に見てみましょう。ログイン処理を行うプログラムの一部です。

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

// ユーザーから送信されたIDとパスワードの認証処理(ダミー)
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';

if (isValidUser($username, $password)) {
    // 【最重要ポイント】セッション固定攻撃を防ぐため、ログイン成功時に必ずセッションIDを再生成する
    // true を指定することで、古いセッションファイルもサーバー側から完全に削除します
    session_regenerate_id(true);

    // ログイン成功後のユーザー情報をセッションに保存
    $_SESSION['is_logged_in'] = true;
    $_SESSION['username'] = $username;

    // マイページへリダイレクト
    header('Location: /mypage.php');
    exit;
} else {
    // ログイン失敗時の処理
    echo "ログインに失敗しました。";
}

このように、認証が成功した直後に session_regenerate_id(true) を呼ぶだけで、セッション固定攻撃に対する強力な盾を手に入れることができます。

—

3. Cookieの頑丈な鍵:HttpOnly, Secure, SameSite属性

セッションIDをブラウザに保存する際には、「Cookie(クッキー)」という仕組みが使われます。このCookieという「宝箱」に鍵をかけ忘れると、別の攻撃(クロスサイトスクリプティングや盗聴など)によってセッションIDが奪われてしまいます。

ここでは、Cookieに設定すべき3つの重要な属性について、分かりやすく整理していきましょう。

① HttpOnly (JavaScriptからの泥棒を防ぐ)

  • 意味: JavaScriptからこのCookieにアクセスすることを禁止する設定です。
  • なぜ必要?: 万が一、Webサイトに「クロスサイトスクリプティング(XSS)」という脆弱性があり、悪意あるスクリプトが実行されてしまったとします。もし HttpOnly がオフになっていると、document.cookie というプログラムによってセッションIDが簡単に盗み出されてしまいます。これをONにしておけば、ブラウザの裏側だけで使われるため、JavaScriptからは触れなくなります。

② Secure (通信の盗聴を防ぐ)

  • 意味: 暗号化された安全な通信(HTTPS)の時だけ、Cookieを送信する設定です。
  • なぜ必要?: カフェのフリーWi-Fiなどの安全ではないネットワーク上で、通信の中身を盗み見られた(スニッフィング)とします。この設定が有効であれば、暗号化されていない通常の通信(HTTP)ではセッションIDが外に飛び出さないため、通信経由での盗難を防げます。

③ SameSite (悪意あるサイトからの勝手な操作を防ぐ – CSRF対策)

  • 意味: 他の外部サイトから自サイトへのリンクを踏んだ際や、画像を読み込ませた際に、Cookieを送信するかどうかを制限する設定です(Strict または Lax を指定します)。
  • なぜ必要?: 悪質なサイトが「このボタンを押して!」とユーザーを誘導し、背後で勝手にあなたの銀行口座から送金ボタンを押させるような攻撃(CSRF)を防ぎます。

—

4. 実務で即座に使える!安全なCookie設定サンプル

それでは、これらの頑丈な鍵をどのように設定すればよいのか、PHPのコード設定例を見てみましょう。PHP 7.3以降では、session_set_cookie_params() 関数を使って、次のようにスマートに一括設定が可能です。

<?php
// セッションCookieのセキュリティパラメータを設定する
// ※ 必ず session_start() を呼ぶ前に設定してください!

$lifetime = 0; // ブラウザを閉じたらセッションを終了する
$path = '/';   // サイト全体のすべてのページで有効にする
$domain = 'example.com'; // 自社のドメインを指定
$secure = true;   // 【Secure属性】HTTPS通信でのみCookieを送信する
$httponly = true; // 【HttpOnly属性】JavaScriptからのアクセスを完全に禁止する

// PHP 7.3以降で利用できる配列形式でのパラメータ設定
session_set_cookie_params([
    'lifetime' => $lifetime,
    'path' => $path,
    'domain' => $domain,
    'secure' => $secure,
    'httponly' => $httponly,
    'samesite' => 'Lax' // 【SameSite属性】LaxまたはStrictを指定してCSRFを防ぐ
]);

// 安全な設定が完了した状態でセッションを開始
session_start();

また、もしPHPのコード側だけでなく、Webサーバー(NginxやApache)やフレームワークの環境設定ファイル(php.iniなど)でグローバルに設定したい場合は、以下のように記述します。

; php.ini における推奨設定
session.cookie_httponly = On
session.cookie_secure = On
session.cookie_samesite = "Lax"

—

5. まとめ:一歩ずつ、安全なWeb開発者へ

今回は、セッション固定攻撃のメカニズムから、ログイン時のセッション再生成、そしてCookieの頑丈な鍵(HttpOnly, Secure, SameSite)の重要性について解説しました。

  • 攻撃の防止: ログイン成功時には必ず session_regenerate_id(true) でセッションIDを新しく作り直す。
  • Cookieの保護: HttpOnly、Secure、SameSite の3点セットを必ず有効にして、ブラウザ上の宝箱を頑丈にロックする。

セキュリティの対策は、一度覚えてしまえば次からの開発でも自然と手が動くようになります。ぜひ今回のコードや考え方を実務のプロジェクトに取り入れて、安全で信頼されるWebアプリケーションを作っていきましょう!一歩ずつ、確実にスキルアップしていってくださいね。応援しています!

コメント

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