CSRFは「死んだ」のか?:ログから読み解く攻撃の予兆と防御の鉄則
「CSRF(クロスサイトリクエストフォージェリ)? 今どきSameSite属性があるし、もう対策済みでしょ」
もし君がそう思っているなら、一度本番環境のWAFログを深く覗いてみることを勧める。現実はもっと泥臭い。攻撃者はブラウザの仕様変更を逆手に取り、依然として「ユーザーのセッションを乗っ取った状態での不正な状態変更」を狙っている。
今日は、教科書的な「トークンを入れろ」という話の先、「実際に攻撃が仕掛けられたとき、どうやってそれを検知し、ログから確信を持って遮断するか」という現場の戦術について話そう。
—
1. なぜ「トークン不一致」だけでは防ぎきれないのか
CSRF対策の基本は「予測不可能なトークンの埋め込み」だが、開発者がやりがちなミスは「エラー時のログ出力が不親切すぎる」ことだ。
攻撃者は、まずトークンが有効か無効かを、レスポンスのステータスコードやエラーメッセージの差異から推測(サイドチャネル攻撃の一種)する。もし君たちのログが「CSRFトークン不一致」という事実だけを淡々と吐き出しているなら、それは攻撃者に「このサイトはCSRF対策を実装している」と教え、別の攻撃手法(例えば、トークンの漏洩経路を探す)へと誘導するヒントを与えているのと同じだ。
ログ分析で見るべき「異常」の相関
単なるトークンエラーと、本当の攻撃を分けるのは以下の相関だ。
- Referer/Originの欠落または外部ドメイン: そもそも、そのリクエストはどこから来たのか?
- 短時間での連続した失敗: 正常なユーザーが、ページをリロードするたびにトークンエラーを連発することはまずない。
- User-Agentの不自然な変化: 自動化ツール(PythonのRequestsライブラリ等)によるリクエストは、ブラウザ特有のヘッダーが欠落していることが多い。
—
2. 実装サンプル:防御と検知を両立させるPHPコード
「コピペで動く」ことは重要だが、「ログに何を残すか」を意識した実装に書き換えよう。
date(‘Y-m-d H:i:s’),
‘ip’ => $_SERVER[‘REMOTE_ADDR’],
‘referer’ => $_SERVER[‘HTTP_REFERER’] ?? ‘None’,
‘ua’ => $_SERVER[‘HTTP_USER_AGENT’],
‘reason’ => ‘CSRF_TOKEN_MISMATCH’
];
// 本番環境ではsyslogや専用のセキュリティログファイルへ送る
error_log(“SECURITY_ALERT: ” . json_encode($logData));
// 攻撃者には具体的な理由を教えず、汎用的な403を返す
http_response_code(403);
die(“Forbidden: Security Violation”);
}
}
// 使用例
if ($_SERVER[‘REQUEST_METHOD’] === ‘POST’) {
verifyCsrfToken($_POST[‘csrf_token’] ?? ”);
// 正常な処理…
}
—
3. インフラ層での防御:NginxによるReferer/Originの厳格化
アプリ層での対策が漏れているケースを想定し、Webサーバー(Nginx)で防波堤を築く。特にAPIエンドポイントにおいて、許可されていないドメインからのリクエストを門前払いするのは非常に有効だ。
Nginx設定ファイル例
location /api/ {
# RefererまたはOriginが自社ドメインでない場合は403を返す
# 許可するドメイン以外からのPOSTを拒否する設定
set $csrf_block 0;
if ($request_method = POST) {
set $csrf_block 1;
}
# 許可されたReferer以外ならフラグを立てる
if ($http_referer !~ ^https://(www\.)?yourdomain\.com) {
set $csrf_block “${csrf_block}1”;
}
# “11” は POSTかつRefererが不正なケース
if ($csrf_block = 11) {
return 403;
}
proxy_pass http://backend_upstream;
}
—
4. チーフエンジニアからの提言:運用の泥臭い勘所
最後に、インシデントハンドリングの経験からアドバイスしたい。
1. 「SameSite=Lax」を過信しない: Chromeのデフォルト設定に救われているだけかもしれない。APIやクロスオリジンのリクエストが必要な設計の場合、Laxでは不十分なケースがある。
2. Refererヘッダーは改ざん可能: 攻撃者は Referer を偽装できる。これだけに依存せず、必ず「トークン」+「Referer」の二段構えで防御すること。
3. WAFのシグネチャをカスタマイズする: AWS WAFやCloudflareを使っているなら、特定のパスへのPOSTリクエストにおいて、「Refererが空」のものをブロックするルールを追加してほしい。これだけで、機械的な攻撃の9割は防げる。
セキュリティ対策は「一度やって終わり」ではない。ログを確認し、攻撃者が「どのドアをノックしているのか」を分析し続ける。その泥臭い積み重ねだけが、君たちのアプリケーションを強固な要塞へと変えていくんだ。
さて、まずは今夜のアクセスログに grep をかけるところから始めようか。どんな異常が見つかるか、楽しみにしているよ。
コメント