
安全监控与分析(Security Monitoring & Analysis)是 SOC 的核心能力。它不等于"堆 SIEM 买告警",而是一套采集 → 规范化 → 检测 → 关联 → 响应的工程体系。本文从日志管道讲起,覆盖检测规则、告警降噪、异常检测与响应编排,给出可落地的代码。
多源日志若不归一化,检测规则无法复用。定义统一事件结构是第一要务。
import json, hashlib
from dataclasses import dataclass, asdict, field
from datetime import datetime, timezone
@dataclass
class SecEvent:
ts: str
source: str # firewall / edr / waf / auth
host: str
user: str
action: str # login / connect / alert
src_ip: str
dst_ip: str
severity: str # info / low / medium / high / critical
raw: dict = field(default_factory=dict)
def fingerprint(self) -> str:
raw = f"{self.source}|{self.host}|{self.src_ip}|{self.ts[:19]}"
return hashlib.sha256(raw.encode()).hexdigest()[:16]
def normalize(source: str, record: dict) -> SecEvent:
"""不同源映射到统一字段"""
mappers = {
"firewall": lambda r: dict(
ts=r["time"], host=r["devname"], user="-", action=r["action"],
src_ip=r["srcip"], dst_ip=r["dstip"], severity="info"),
"auth": lambda r: dict(
ts=r["timestamp"], host=r["hostname"], user=r["user"],
action=r["event"], src_ip=r.get("ip", "-"), dst_ip="-",
severity="medium" if r["event"] == "failed" else "info"),
}
fields = mappers[source](record)
return SecEvent(source=source, raw=record, **fields)统一 Schema 后,规则、存储、可视化、报表全部复用同一套字段,避免"每接一个源就重写一次逻辑"。
检测规则应数据驱动、可版本化、与代码分离。用 YAML 定义规则,Python 执行匹配。
# rules/brute_force.yml
title: 多次登录失败后成功
id: auth-brute-001
level: high
source: auth
condition:
group_by: [user, src_ip]
window: 300
sequence:
- match: {action: failed, count: ">=5"}
- match: {action: success}import yaml, time
from collections import defaultdict
class RuleEngine:
def __init__(self, rule_path):
with open(rule_path) as f:
self.rule = yaml.safe_load(f)
self.buckets = defaultdict(list)
def feed(self, ev: SecEvent):
if ev.source != self.rule["source"]:
return None
cond = self.rule["condition"]
key = tuple(getattr(ev, k) for k in cond["group_by"])
now = time.time()
self.buckets[key].append((now, ev.action, ev))
# 清理窗口外数据
window = cond["window"]
self.buckets[key] = [(t, a, e) for t, a, e in self.buckets[key]
if now - t <= window]
seq = cond["sequence"]
actions = [a for _, a, _ in self.buckets[key]]
return self._match_sequence(seq, actions)
def _match_sequence(self, seq, actions):
"""简化版:按顺序检查每步是否满足"""
i = 0
for step in seq:
rule = step["match"]
count = int(rule.get("count", ">=1").replace(">=", ""))
hits = sum(1 for a in actions[i:] if a == rule["action"])
if hits < count:
return None
i += hits
return {"rule": self.rule["title"], "level": self.rule["level"]}规则即配置,新增检测无需改代码,便于团队协作与审计。
原始告警量巨大,必须聚合。核心思路:同实体、同时间窗、多规则命中 → 升级为事件。
class Correlator:
def __init__(self, window=300, threshold=3):
self.window = window
self.threshold = threshold
self.buf = defaultdict(list)
def add(self, entity: str, alert: dict, ts: float = None):
ts = ts or time.time()
self.buf[entity].append((ts, alert))
self.buf[entity] = [(t, a) for t, a in self.buf[entity]
if ts - t <= self.window]
def incidents(self) -> list[dict]:
out = []
for entity, items in self.buf.items():
if len(items) < self.threshold:
continue
levels = [a["level"] for _, a in items]
level = ("critical" if "critical" in levels else
"high" if "high" in levels else "medium")
out.append({"entity": entity, "count": len(items),
"level": level,
"rules": sorted({a["rule"] for _, a in items})})
return out降噪的本质是把"告警"变成"事件":分析师处理的是有上下文的事件,而非孤立的告警。
规则覆盖已知,基线捕捉未知。用滚动统计识别偏离。
import numpy as np
from collections import deque
class BaselineDetector:
def __init__(self, window=100, z_threshold=3.5):
self.history = deque(maxlen=window)
self.z = z_threshold
def update(self, value: float) -> float | None:
"""返回 z-score,超过阈值即异常"""
if len(self.history) < 20:
self.history.append(value)
return None
med = np.median(self.history)
mad = np.median(np.abs(np.array(self.history) - med)) or 1e-9
z = 0.6745 * (value - med) / mad
self.history.append(value)
return z if abs(z) > self.z else None用 MAD 而非标准差,对尖刺不敏感,适合流量、登录次数这类波动大的指标。
告警需附带上下文才能判断。查询 IP 信誉并注入告警:
import httpx
from functools import lru_cache
@lru_cache(maxsize=4096)
def ip_reputation(ip: str) -> dict:
# 示例:接入任意威胁情报API
try:
r = httpx.get(f"https://api.example.com/ip/{ip}", timeout=3)
return r.json()
except Exception:
return {"score": 0, "tags": []}
def enrich(alert: dict) -> dict:
ip = alert.get("src_ip")
if ip:
rep = ip_reputation(ip)
alert["intel"] = rep
if rep.get("score", 0) > 80:
alert["level"] = "critical"
return alert富化让分析师的决策从"这个IP是谁"变成"这个IP是已知C2,立即隔离"。
检测的终点是响应。高危动作必须走审批,低危可自动化。
class Playbook:
def __init__(self, name, steps):
self.name = name
self.steps = steps # [(action_name, fn, requires_approval)]
def run(self, alert, auto=True):
log = []
for name, fn, need_approval in self.steps:
if need_approval and not auto:
log.append(f"[待审批] {name}")
break
try:
result = fn(alert)
log.append(f"[完成] {name}: {result}")
except Exception as e:
log.append(f"[失败] {name}: {e}")
break
return log
def block_ip(alert):
# 实际调用防火墙API封禁
return f"已封禁 {alert['src_ip']}"
def notify(alert):
return "已通知值班"
playbook = Playbook("brute_force_response", [
("封禁源IP", block_ip, True), # 需审批
("通知值班", notify, False), # 自动
])分级响应原则:只读动作自动执行,写动作与破坏性动作必须人工确认,避免误封导致业务中断。
安全监控与分析的专业性,体现在Schema 的统一、规则的数据驱动、告警的关联降噪、检测的分层互补、响应的分级可控。规则覆盖已知,基线捕捉未知,情报提供上下文,编排沉淀动作。把这条链路跑通,SOC 才能从"告警消防队"升级为"主动防御体系"。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。