インシデントの「点」を「線」に変える:フォレンジック的思考に基づくタイムライン分析の極意
現場でエンジニアをしていると、「攻撃を受けているようだ」というアラートの後に必ず直面するのが、バラバラになったログの破片を繋ぎ合わせる地獄のパズルだ。
攻撃者は、痕跡を消すために logrotate を操作したり、タイムスタンプを改ざん(Timestomp)したりする。だが、彼らがどれだけ巧妙に振る舞おうとも、複数のシステムが刻む「クロック」のズレと、イベント間の「因果関係」までは完全に隠蔽できない。
今日は、インシデントハンドリングの最前線で使っている、ログの整合性を確保し、攻撃の全貌を暴くための技術的な勘所を共有しよう。
—
1. タイムスタンプの「正規化」という名の聖戦
多くのエンジニアが犯す最大の過ちは、複数のサーバから出力されたログを、それぞれのローカル時刻のまま分析することだ。
Webサーバが UTC、DBサーバが JST、クラウドの CloudTrail が UTC で記録されている場合、イベントの相関など取れるはずがない。攻撃者が「Webへのアクセス」と「DBのクエリ実行」をミリ秒単位で同期させているとき、この数時間のズレは致命的だ。
実践:タイムスタンプ正規化のルール
すべてのログは、収集段階(SIEMやログ集約サーバ)で必ず ISO 8601 形式の UTC に統一せよ。
Nginx のログフォーマット設定例:
# /etc/nginx/nginx.conf
# $time_iso8601 を使用して、タイムゾーンの曖昧さを排除する
log_format main_json escape=json '{'
'"time_local":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":"$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"http_user_agent":"$http_user_agent"'
'}';
—
2. 攻撃者が好む「足跡」の消し方と防衛策
攻撃者はしばしば、侵入後に history を削除したり、touch -d コマンドでファイルの更新日時を改ざんする。これに対抗するには、アプリケーションレベルで「改ざん不可能なログ」を構築しておく必要がある。
PHPによる「改ざん検知ログ」の実装
単なるファイル書き込みではなく、ハッシュチェーンを用いたログ記録を行うことで、ログが途中で削られたり改ざんされたりした際に即座に検知できる。
<?php
/**
* 前回のログのハッシュを保持し、連鎖的にハッシュを計算することで
* ログの改ざんを後から検知可能にする簡易実装
*/
function log_secure_event($message, $previous_hash) {
$timestamp = gmdate('Y-m-d\TH:i:s\Z');
$log_entry = $timestamp . " | " . $message . " | " . $previous_hash;
// 現在のログのハッシュを生成
$current_hash = hash('sha256', $log_entry);
// ログを外部の安全なストレージ(またはWORM属性のストレージ)へ追記
file_put_contents('/var/log/app_secure.log', $log_entry . " | " . $current_hash . PHP_EOL, FILE_APPEND);
return $current_hash;
}
// 利用イメージ
$last_hash = '0000000000000000'; // 最初のハッシュ
$last_hash = log_secure_event("User login: admin", $last_hash);
?>
—
3. インシデント相関:横展開(Lateral Movement)を追う
攻撃者はまず Web 経由で侵入し、その後内部の 169.254.169.254(メタデータサービス)を叩いてIAM権限を奪取しようとする。
ここで重要なのは、「Webサーバのアクセスログ」と「クラウドのAPI操作ログ(CloudTrail等)」を紐付けることだ。
防御のための IAM 最小権限設定(最小のログ出力)
攻撃者が権限昇格を試みた際、特定のログが記録されるように IAM ポリシーで条件を絞る。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictMetadataAccess",
"Effect": "Deny",
"Action": "sts:AssumeRole",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:SourceVpc": "vpc-0123456789abcdef"
}
}
}
]
}
*解説:この設定は、指定したVPC外からの権限昇格を拒否する。攻撃者が横展開を試みた瞬間に CloudTrail に AccessDenied エラーが残り、これが攻撃の「トリガーイベント」となる。*
—
最後に:エンジニアが持つべき「疑う」姿勢
システム運用において、ログは単なる記録ではない。それは「攻撃者との対話の記録」だ。
- なぜこの時間に
curlが叩かれたのか? - なぜこのプロセスの親プロセスが
www-dataなのか? - なぜ
User-Agentがpython-requests/2.xなのか?
これらの疑問を抱き、ログを時系列に並べて「ストーリー」を再構築できたとき、初めてあなたは「インシデントハンドラー」として一人前になれる。
まずは今すぐ、あなたのサーバのログフォーマットを確認し、ISO 8601 に準拠しているか見直すことから始めてほしい。それが、最悪の事態に直面したときに、あなたを救う唯一の命綱になる。
コメント