WebVulnerabilities

セッション固定攻撃について

概要

セッション固定攻撃(Session Fixation)は、攻撃者がユーザーに特定のセッションIDを強制的に使用させ、そのセッションIDを用いて攻撃者がユーザーのアカウントに不正にアクセスする攻撃手法です。この攻撃は、WebアプリケーションがセッションIDをユーザーの認証後に再生成しない場合に発生します。攻撃者は、ユーザーがログインする前に固定したセッションIDを取得し、その後ユーザーが認証した後にそのセッションを乗っ取ることができます。


脆弱性を持つコードの例と攻撃手法

PHP

脆弱なコード例:

<?php
// PHPの設定でURLパラメータからセッションIDを受け取る設定が有効な場合
ini_set('session.use_cookies', 0);  // クッキーを無効にする
ini_set('session.use_only_cookies', 0);  // セッションIDをURLパラメータから受け取る設定を有効にする
ini_set('session.use_trans_sid', 1);  // セッションIDをURLからも受け取る設定を有効にする

session_start(); // セッションを開始または既存のセッションを使用

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // ユーザー認証が成功した場合
    $_SESSION['username'] = $_POST['username'];
    echo "Logged in as " . $_SESSION['username'];
} else {
    echo "Please log in.";
}
?>

攻撃手法:

  1. 攻撃者は、ユーザーに特定のセッションIDを含むURLを送信します。
    http://example.com/login.php?PHPSESSID=123456789
    
  2. ユーザーがこのURLをクリックしてログインすると、攻撃者が固定したセッションID(123456789)が使用されます。
  3. 攻撃者はこのセッションIDを使用して、ユーザーのセッションにアクセスできます。

Python(Flask)

脆弱なコード例:

from flask import Flask, session, request

app = Flask(__name__)
app.secret_key = 'supersecretkey'

@app.route('/login', methods=['POST'])
def login():
    if request.form['username'] == 'admin' and request.form['password'] == 'password':
        session['username'] = request.form['username']
        return f"Logged in as {session['username']}"
    return 'Invalid credentials'

if __name__ == '__main__':
    app.run()

攻撃手法:

  1. 攻撃者は、ユーザーに特定のセッションIDを含むURLを送信します。
    http://example.com/login?sessionid=abcd1234
    
  2. ユーザーがこのURLをクリックしてログインすると、攻撃者が固定したセッションID(abcd1234)が使用されます。
  3. 攻撃者はこのセッションIDを使用して、ユーザーのセッションにアクセスできます。

Node.js(Express)

脆弱なコード例:

const express = require('express');
const session = require('express-session');
const app = express();

app.use(session({ secret: 'supersecretkey', resave: false, saveUninitialized: true }));

app.post('/login', (req, res) => {
    if (req.body.username === 'admin' && req.body.password === 'password') {
        req.session.username = req.body.username;
        res.send(`Logged in as ${req.session.username}`);
    } else {
        res.send('Invalid credentials');
    }
});

app.listen(3000);

攻撃手法:

  1. 攻撃者は、ユーザーに特定のセッションIDを含むURLを送信します。
    http://localhost:3000/login?sessionid=xyz789
    
  2. ユーザーがこのURLをクリックしてログインすると、攻撃者が固定したセッションID(xyz789)が使用されます。
  3. 攻撃者はこのセッションIDを使用して、ユーザーのセッションにアクセスできます。

Java(Spring)

脆弱なコード例:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;

@Controller
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password, HttpSession session) {
        if ("admin".equals(username) && "password".equals(password)) {
            session.setAttribute("username", username);
            return "Logged in as " + username;
        }
        return "Invalid credentials";
    }
}

攻撃手法:

  1. 攻撃者は、ユーザーに特定のセッションIDを含むURLを送信します。
    http://localhost:8080/login;jsessionid=abc123
    
  2. ユーザーがこのURLをクリックしてログインすると、攻撃者が固定したセッションID(abc123)が使用されます。
  3. 攻撃者はこのセッションIDを使用して、ユーザーのセッションにアクセスできます。

防止策

  1. 認証後のセッションIDの再生成:
    • ユーザーがログインした後、必ずセッションIDを再生成することで、攻撃者が固定したセッションIDを無効化します。

    PHPの例:

    session_regenerate_id(true); // セッションIDの再生成
    

    Pythonの例(Flask): Flaskのセッションは標準でsession.regenerate_id()に相当する操作がサポートされていないため、セッション再生成のためのカスタムロジックを追加する必要があります。

    Node.jsの例(Express):

    req.session.regenerate((err) => {
        // セッションIDが再生成されました
    });
    

    Javaの例(Spring):

    session.invalidate(); // セッションを無効化
    session = request.getSession(true); // 新しいセッションを作成
    
  2. セッション固定を防ぐ設定の使用:
    • 多くのフレームワークやライブラリには、セッション固定攻撃を防ぐための設定が存在します。これらの設定を有効にします。
  3. クッキーのセキュリティ設定:
    • セッションIDが含まれるクッキーには、HttpOnlyおよびSecure属性を設定し、クッキーがJavaScriptからアクセスされることや、非HTTPS経由で送信されることを防ぎます。

    PHPの例:

    ini_set('session.cookie_httponly', 1);
    ini_set('session.cookie_secure', 1);
    

    Node.jsの例(Express):

    app.use(session({
        secret: 'supersecretkey',
        cookie: { httpOnly: true, secure: true }
    }));
    
  4. セッションIDのURLパラメータでの送信を避ける:
    • セッションIDをURLに含めて送信することは避け、必ずクッキーを使用してセッションIDを管理します。URLにセッションIDを含めると、他人と共有されやすくなり、セキュリティリスクが高まります。

まとめ: セッション固定攻撃は、攻撃者がユーザーに特定のセッションIDを使用させることで、そのセッションを乗っ取る攻撃です。認証後のセッションIDの再生成、セッション固定防止設定の使用、セッションIDのクッキー管理などの防止策を実施することで、この脆弱性を効果的に防ぐことが可能です。各言語やフレームワークでの適切な対策を講じることが推奨されます。