「ログは出しているが、誰も見ていない」を卒業する。侵害の予兆を掴むログパイプラインの実践的設計
インシデント対応の現場で最も絶望するのは、「攻撃が完了してからログを解析する」ことだ。攻撃者は痕跡を消す。ログがローカルにしか存在しなければ、侵害された瞬間にそのログ自体が改ざん、あるいは削除される。
SIEM(Security Information and Event Management)への転送は、単なるコンプライアンス対応ではない。「敵が侵入した瞬間に、その足跡を外部の安全な領域へ避難させる」という、究極の防衛線だ。今回は、私が現場で徹底している「ログの生存戦略」と、Vectorを用いた堅牢なパイプライン構築について伝授する。
—
攻撃者は「ノードの隙間」を縫う
攻撃者は、OSの脆弱性(CVE)やWebアプリのインジェクションを足がかりに、まずは「権限昇格」を狙う。その後、彼らはrm -rf /var/log/*を打つ前に、まずシェル履歴を隠滅する。
もし君たちが、ログを収集するだけで「転送」の仕組みを疎かにしていれば、攻撃者が特権を得た瞬間に、君たちの監視網は無力化する。SIEMへのリアルタイム転送がなぜ重要か? それは、攻撃者が自身の痕跡を消すよりも速く、異常のシグナルを別の場所へ退避させるためだ。
—
Vectorによる「倒れない」ログ収集パイプライン
Fluentdも良いが、Go言語で書かれ、メモリ効率と堅牢性に優れた Vector を私は推奨する。特にコンテナ環境では、サイドカーパターンでVectorを動かし、OSログとアプリログを分離してSIEMへ流し込むのが定石だ。
1. Vectorによるログ転送設定 (vector.toml)
ただログを垂れ流すのではなく、転送前に「機密情報のマスク」と「構造化」を行う。これができていないログは、SIEM側での相関分析を困難にするノイズでしかない。
# ログソース:syslogとDockerコンテナログを同時監視
[sources.os_logs]
type = "file"
include = ["/var/log/auth.log", "/var/log/syslog"]
[sources.app_logs]
type = "docker_logs"
# 変換:機密情報のマスク(正規表現でメールアドレスやクレカ番号を伏せる)
[transforms.mask_sensitive_data]
type = "remap"
inputs = ["app_logs"]
source = '''
.message = replace!(.message, r"(\d{4}-){3}\d{4}", "****-****-****-****")
'''
# 出力:SIEM(ここではDatadogやElasticsearchを想定)へ転送
[sinks.siem_backend]
type = "elasticsearch"
inputs = ["mask_sensitive_data", "os_logs"]
endpoints = ["https://your-siem-endpoint:9200"]
# ネットワーク切断時に備え、メモリバッファを持たせる
[sinks.siem_backend.buffer]
type = "memory"
max_events = 500
—
防御の要:SIEMで検知すべき「3つの異常」
ログを転送しただけで満足してはいけない。SIEM側で以下のルールを実装せよ。特に、WebアプリのログとOSの認証ログを「相関」させるのがコツだ。
1. 異常な認証試行: auth.log における特定のIPからの「Failed password」が1分間に5回以上発生した場合。
2. Web攻撃の成功: Nginxのログで 404 や 403 が連続した直後に、200 応答かつレスポンスサイズが異常に大きい(データ持ち出しの予兆)場合。
3. 権限昇格の予兆: sudo の使用ログが、普段の業務時間外や、特定のセッションID以外から発生した場合。
—
実践:PHPアプリでのログ出力の作法
アプリ開発者が error_log() を適当に書くと、インフラ側のログ収集が破綻する。必ずJSON形式で出力し、コンテキストを持たせるルールを徹底させること。
<?php
/**
* セキュアなログ出力サンプル
* 攻撃者がユーザー入力値をログに紛れ込ませる「Log Injection」を防ぐために、
* 入力値の改行コードを除去し、JSONで構造化する。
*/
function secure_logger($level, $message, $context = []) {
$log_entry = [
'timestamp' => date('Y-m-d H:i:s'),
'level' => $level,
'message' => str_replace(["\r", "\n"], '', $message), // CRLFインジェクション対策
'user_id' => $_SESSION['user_id'] ?? 'anonymous',
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
'context' => $context
];
// JSONとして出力することで、Vector側でのパースが容易になる
error_log(json_encode($log_entry));
}
// 使用例
secure_logger('WARNING', 'ログイン失敗', ['username' => $_POST['username']]);
—
最後に:エンジニアへの提言
セキュリティは「設定して終わり」の静的なものではない。攻撃手法は日々進化する。君たちが構築したログパイプラインも、いつか攻撃者にその存在を認識され、ログの「送信元」を偽装されたり、ログ送信自体をブロックするような攻撃を受けるかもしれない。
「ログは絶対に改ざんされ、削除される」という性悪説に立ち、SIEM側での「ログ受信の欠落検知(Heartbeat監視)」までセットで構築して初めて、君たちのシステムは「戦える」状態になる。
現場の泥臭い戦いにおいて、最後に自分を守るのは「ログの分析能力」と「異常を即座に感知する直感」だ。まずは今日、手元のサーバーの /var/log/auth.log が正しく中央集権的な場所に転送されているか、その確認から始めてほしい。
コメント