こんにちは!セキュリティの世界へようこそ。
初めてインシデント対応やログ解析の世界に足を踏み入れると、英字の羅列や見慣れない専門用語の多さに圧倒されてしまいますよね。「自分に使いこなせるだろうか…」と不安になることもあるかもしれませんが、安心してください。一歩ずつ、身近な例から紐解いていけば、決して難しくはありません。
今回は、日々のシステム運用やフォレンジック調査で必ず直面する「HTTP/HTTPS通信のUser-Agentとヘッダーの異常解析」について、現場のリアルな視点を交えながら、優しく丁寧に解説していきますね。
—
1. そもそも「HTTPヘッダー」ってなに?(お家に例えてみよう)
インターネットの世界で、あなたのパソコンやスマホがWebサイトと会話するとき、必ず「HTTP(エイチ・ティー・ティー・ピー)」という共通ルールでおしゃべりをしています。
このとき、会話の本体だけでなく、必ず「封筒の表書き」のような情報が一緒に送られています。これが「HTTPヘッダー」です。
想像してみてください。あなたのお家に、宅急便の荷物が届いたとします。
ダンボールの送り状には、次のような情報が書かれていますよね。
- お届け先・ご依頼主(IPアドレスや宛先)
- 品名(何のデータを見たいのか)
- お届け方法・備考欄(どのブラウザを使っているか、どんな言語を話すかなど)
この「備考欄」にあたる部分の代表格が、User-Agent(ユーザーエージェント)です。
通常、私たちがGoogle ChromeやSafariなどのブラウザを使ってWebサイトにアクセスすると、User-Agentには「私は今、このブラウザのこのバージョンを使って、このOSからアクセスしていますよ」という名刺が自動で記載されます。
泥棒(攻撃者)があなたのシステムにこっそり侵入しようとするとき、この名刺(User-Agent)や封筒の書き方に、実は「隠しきれない不自然さ」が残ってしまうのです。ここを見抜くのが、私たちDFIR(インシデントレスポンス)アナリストの腕の見せ所というわけですね。
—
2. 攻撃者が使う「不自然なヘッダー」の正体
安全なお散歩(正当なアクセス)をしている人は、決まった服を着て、決まった挨拶をします。しかし、悪意を持った侵入者は、目出し帽をかぶっていたり、手作りの怪しげなパスポート(自作のスクリプトや攻撃ツール)を持っていたりします。
プロキシログやPCAP(パケットキャプチャファイル)を覗いたとき、次のような「異常」を見つけたら要注意です。
パターンA:丸裸のUser-Agent(あるいは空っぽ)
普通の人間や正規のブラウザは、必ず自分が何者であるかを名乗ります。しかし、初心者の開発者が作った雑なスクリプトや、海外の自動攻撃ボットの中には、User-Agent欄を空っぽ(NoneやNull)のまま突っ込んでくるものがいます。
「私は誰にも名乗りません」と言いながらドアをノックしているようなものですから、怪しさ満点ですよね。
パターンB:有名だけど古すぎる、あるいは矛盾した名刺
「私はWindows 95のInternet Explorerです!」と主張しながら、最新の暗号化通信の仕組みを使ってアクセスしてくるボットがいます。時代錯誤も甚だしいですよね。OSとブラウザの組み合わせが物理的にあり得ないものも、攻撃ツール特有の「やっつけ仕事」の証拠です。
パターンC:攻撃ツール特有のシグネチャ(足跡)
セキュリティ診断や不正アクセスによく使われる有名なツール(例えば、脆弱性スキャナーやペネトレーションテスト用のツール)は、デフォルトで独特なUser-Agent文字列を送信します。
例えば、ツールの名前そのものが文字列に含まれていたり、ヘッダーの順番が通常のブラウザと全く違っていたりします。
—
3. 実践!怪しい通信をログから炙り出す
それでは、実際の現場でどのようにこれらを見つけ出すのか、具体的なコードや設定を見ていきましょう。
今回は、Webアプリケーションの入り口(Webサーバーやリバースプロキシ)で、怪しいUser-Agentを弾いたり記録したりするためのサンプルを見ていきます。
例:PHPでのシンプルなUser-Agent検証・ブロックの仕組み
もし自社で軽量なAPIやWebサイトを運営している場合、不審なリクエストを初期段階で弾くコードは次のように書くことができます。
<?php
// リクエストに含まれるUser-Agentを取得する(取得できない場合は空文字にする)
$userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
// 1. User-Agentが空っぽ、または極端に短すぎる場合はブロック(ボットの可能性高)
if (empty($userAgent) || strlen($userAgent) < 5) {
// ログに不正なアクセスの兆候として記録する
error_log("【警告】不審な空User-Agentを検出しました。IP: " . $_SERVER['REMOTE_ADDR']);
// アクセスを拒否して403を返す
header("HTTP/1.1 403 Forbidden");
echo "Access Denied: Invalid User-Agent";
exit;
}
// 2. 既知の攻撃ツールや悪名高いスキャナーのキーワードリスト(一部)
$forbiddenKeywords = [
'sqlmap', // 自動SQLインジェクションツール
'nikto', // Webサーバー脆弱性スキャナー
'masscan', // 高速ポートスキャナー
'python-requests' // 開発用ライブラリ(社内API以外からの直接アクセスは要警戒)
];
// キーワードが含まれているかループでチェックする
foreach ($forbiddenKeywords as $keyword) {
// 大文字小文字を区別せずにチェック
if (stripos($userAgent, $keyword) !== false) {
error_log("【警告】攻撃ツールのシグネチャを検出: {$keyword} / IP: " . $_SERVER['REMOTE_ADDR']);
header("HTTP/1.1 403 Forbidden");
echo "Access Denied";
exit;
}
}
// 正常なアクセスの処理
echo "ようこそ!安全な接続が確認されました。";
?>
このように、まずは「怪しい名前を名乗っていないか」「そもそも名乗っているか」を確認するだけでも、無駄な攻撃の大部分を玄関先で追い返すことができます。
—
4. Webサーバー(Nginx)でのリクエスト制限設定
もしインフラ寄りの設定を任された場合は、Webサーバーの機能を使って、よりスマートに異常なリクエストをフィルタリングしましょう。
以下は、NginxというWebサーバーで、怪しいUser-Agentを持つアクセスを一網打尽にする設定例です。
# nginx.conf またはバーチャルホストの設定ファイル内
# マップブロックを使って、悪質なUser-Agentを判定する変数を作る
map $http_user_agent $bad_bot {
default 0;
# 正規表現で空文字や怪しいツール名をマッチさせる
"~^$" 1; # 空のUser-Agent
"~*sqlmap" 1; # sqlmap
"~*nikto" 1; # Nikto
"~*scanner" 1; # 一般的なスキャナー名
"~*python-requests" 1; # 生のPythonスクリプトによるアクセス
}
server {
listen 80;
server_name example.com;
location / {
# もし $bad_bot が 1(true)だったら、問答無用で403を返す
if ($bad_bot) {
return 403;
}
# 通常のルーティング設定
try_files $uri $uri/ =403;
}
}
現場のインフラ担当者としては、こうした設定をWAF(Webアプリケーションファイアウォール)やリバースプロキシのレイヤーで最初から有効化しておくことが、夜中にアラートで叩き起こされないための最大の防御策になります。
—
5. まとめと、明日からできる一歩
HTTP/HTTPS通信におけるUser-Agentやヘッダーの異常解析は、フォレンジック調査の「最初の入り口」であり、一番最初に目につく手掛かりです。
- 「ちゃんとした名刺(User-Agent)を持っているか?」
- 「おかしな道具(攻撃ツール名)を隠し持っていないか?」
家の防犯に例えるなら、インターホン越しに「どちら様ですか?」としっかり確認する作業そのものです。
最初はログの海からおかしな記述を見つけるのは大変に思えるかもしれませんが、日頃から「普通の通信」がどういうものかを見慣れておけば、「おや、この行だけ様子が変だぞ」という違和感にすぐ気づけるようになります。
焦らず、一歩ずつ、目の前のログを丁寧に観察していきましょう。あなたのその地道な確認作業が、組織のセキュリティを守る最高の盾になります。それでは、次回の解説もお楽しみに!
コメント