現場で泥をすすりながらインシデント対応をしていると痛感するんだが、セキュリティの質は「ログの量」ではなく「ログの解像度」で決まる。
SIEM(Security Information and Event Management)を導入しても、ただログを流し込んで「異常検知」という名のノイズに溺れている現場があまりに多すぎる。今日は、ECS(Elastic Common Schema)をベースに、攻撃者が最も嫌がる「相関分析」の極意を伝授しよう。
—
1. なぜ「正規化」が攻撃者の急所を突くのか
攻撃者は、システム間に存在する「言葉の壁」を突いてくる。Webサーバーの access.log と、DBの query.log、そしてIAMの audit.log は、それぞれ出力形式がバラバラだ。
バラバラなままでは、「Webサーバーで不審なPOSTがあった直後に、DBで権限昇格コマンドが叩かれた」という一連のストーリーをSIEMが理解できない。攻撃者は「単発の小さな異常」を積み重ねて目的を達成する。正規化とは、バラバラな断片を「物語」として再構成するための翻訳作業なんだ。
2. 実践:ECSに基づいたログの構造化
まずは、アプリケーションレベルで送出するログをECS準拠のJSON形式に揃える必要がある。Pythonの structlog などを使って、最初から構造化ログを吐かせるのが鉄則だ。
以下は、ログイン試行を記録する際のセキュアな構造例だ。
import json
import time
def log_login_attempt(user_id, source_ip, status):
# ECSに準拠したフィールド構成
# event.category: 認証関連
# user.id: ユーザー識別子
# source.ip: 送信元IP
# event.outcome: success または failure
log_entry = {
"@timestamp": time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
"event": {
"category": ["authentication"],
"outcome": status,
"action": "login_attempt"
},
"user": {"id": user_id},
"source": {"ip": source_ip},
"message": f"Login attempt for user {user_id} from {source_ip}"
}
print(json.dumps(log_entry))
# 使用例:認証失敗を記録
log_login_attempt("admin_user", "192.168.1.50", "failure")
3. 「相関分析」の真骨頂:ブルートフォース+権限昇格
単なる「ログイン失敗が10回続いたらアラート」は、今どき攻撃者は余裕で回避する。我々が狙うべきは「時系列の相関」だ。
例えば、「特定のIPから短時間の認証失敗(失敗の兆候)の直後に、管理権限が必要なAPIへのアクセス(成功)が発生したケース」を検知するルールを設計する。
SIEM用相関ルールのロジック(疑似クエリ)
-- 5分以内に、同じ送信元IPでログイン失敗が3回発生し、
-- その後10分以内にadmin権限操作が行われた場合を検知
SELECT
source.ip,
user.id
FROM logs
WHERE event.category = 'authentication'
MATCH
(
SELECT count(*) as fail_count FROM logs
WHERE event.outcome = 'failure'
GROUP BY source.ip, window(5m)
HAVING fail_count >= 3
) AS A
FOLLOWED BY
(
SELECT * FROM logs
WHERE event.action = 'privilege_escalation'
AND event.outcome = 'success'
) AS B
ON A.source.ip = B.source.ip
WITHIN 10m
このルールが現場で生きるのは、「パスワードリスト攻撃で突破された瞬間」をピンポイントで射抜けるからだ。
4. 防御の壁:WAFと連携した動的ブロック
ログを眺めるだけでは不十分だ。相関ルールで「黒」と判定されたら、そのIPを即座にWAF(例えばAWS WAFやNginxの deny)へ流し込み、自動遮断させる実装が必要だ。
Nginxで動的にブロックリストを読み込む設定例を紹介しよう。
# /etc/nginx/conf.d/blocklist.conf を動的に更新する運用
# Luaモジュール等を使って、SIEMからのAPIコールでこのファイルを書き換える
include /etc/nginx/conf.d/blocklist.conf;
server {
location / {
# 異常検知されたIPはここに含まれる
if ($is_blocked) {
return 403;
}
...
}
}
5. チーフからの教訓:ログは「武器」にせよ
いいか、最後に一つだけ覚えておいてほしい。セキュリティとは「100%防ぐこと」ではない。「何が起きたか」を誰よりも早く、正確に理解し、即座に対処する「追跡能力」を構築することだ。
ログの正規化を怠るエンジニアは、戦場で地図を持たずに戦う兵士と同じだ。ECSを導入し、相関ルールを磨き上げろ。最初は面倒だが、一度この「可視化のパイプライン」ができると、攻撃者がどんなに巧妙な手口を使ってきても、君たちの前ではすべてが「透明な挙動」になるはずだ。
次は、このログパイプラインを破壊しにくる「ログ改ざん攻撃」への対抗策について深掘りしよう。それまでに、まずは今のシステムのログを一箇所に集約し、JSONで統一することから始めてくれ。それが君たちの最初の防衛線だ。
コメント