TsekrekosEA/NetWatch
GitHub: TsekrekosEA/NetWatch
NetWatch是一个结合统计基线与机器学习的双阶段网络入侵检测系统,支持实时流量分析、威胁情报富化及可视化监控。
Stars: 2 | Forks: 0
# NetWatch — 网络异常检测与入侵检测系统
一个两阶段的网络入侵检测系统,结合了统计基线与 ML 异常评分、实时 WebSocket 流、IP 威胁情报充实,以及 Prometheus/Grafana 可观测性堆栈——基于真实的数据包捕获和 CIC-IDS-2018 基准数据集构建。

## 架构

## 工作原理
### 阶段 1 — 统计基线检测
每个传入的网络流都表示为一个 20 维特征向量(字节数、数据包速率、到达时间间隔、TCP 标志分布)。包含最近 1,000 个流的滚动窗口会维护每个特征的均值和标准差。任何特征偏离基线超过 3.5 个标准差的流都会被标记。这可以立即捕获基于流量的攻击(端口扫描、SYN 洪水、DoS),且无需任何训练数据。
### 阶段 2 — ML 分类器
在 CIC-IDS-2018 数据集上训练了两个模型:
- **Isolation Forest** (无监督):仅使用良性流量进行训练。模拟一个点能多容易地与正常行为的集群隔离——异常点通常很容易被隔离。低于 `IF_THRESHOLD` 的分数会触发警报。
- **Random Forest** (有监督):在所有 14 个标记的攻击类别上进行训练。为已知签名提供特定的攻击分类。低置信度预测(低于 `RF_CONFIDENCE_THRESHOLD`)会被抑制以减少误报。
这两个阶段是互补的:阶段 1 会立即捕获流量异常;阶段 2 会捕获从流量上看正常但基于模式的攻击(慢速扫描、暴力破解、C2 信标)。
### 警报速率限制
在可配置的时间窗口(`ALERT_RATE_LIMIT_SECONDS`)内,对同一 `(src_ip, category)` 对的重复警报会被抑制。抑制表限制为 5,000 个条目,并采用 LRU 淘汰机制。
### IP 威胁情报
当打开警报详情模态框时,NetWatch 会实时充实源 IP 信息:
- 通过 ip-api.com 获取 **GeoIP**(无需 API 密钥):国家、地区、城市、ISP、组织、ASN
- **AbuseIPDB**(可选,设置 `ABUSEIPDB_API_KEY`):滥用置信度分数(0–100%)、报告数量、Tor 出口节点标记
- 结果在内存中缓存 1 小时;跳过私有/RFC-1918 地址
### 可观测性
- **Prometheus** 每 10 秒抓取一次 `/metrics`
- **Grafana** 附带一个预配置的 NetWatch 仪表板,每 10 秒自动刷新一次:
- 流量/秒、警报/分钟、速率受限计数、ML 加载状态、活跃的 WS 连接数
- 时间序列:按协议分类的流量、按严重程度分类的警报
- 百分位延迟(p50 / p95 / p99)
- 饼图:按检测阶段、按严重程度、按攻击类别
## 技术栈
| 层级 | 技术 | 原因 |
|---|---|---|
| 数据包捕获 | Scapy + libpcap | 可脚本化,跨平台 |
| 流量引擎 | Python + NumPy | 完全控制特征提取 |
| 阶段 1 | 统计 (z-score) | 快速、可解释、无需训练 |
| 阶段 2 | scikit-learn (IF + RF) | 标准、易于理解、可导出 |
| 数据集 | CIC-IDS-2018 | IDS 研究的学术标准 |
| 警报存储 | SQLite (WAL 模式) | 零依赖、便携、写入速度快 |
| 后端 | FastAPI | 异步、原生支持 WebSocket |
| 实时推送 | WebSocket | 低延迟警报流 |
| 威胁情报 | ip-api.com + AbuseIPDB | GeoIP 充实、无需强制密钥 |
| 可观测性 | Prometheus + Grafana | 行业标准、预配置 |
| 前端 | React + TypeScript + Vite | 包含 Recharts 的实时仪表板 |
| 容器 | Docker + docker-compose | 一条命令运行所有内容 |
| 测试 | pytest + pytest-asyncio | 50 个测试涵盖流水线、模型、API |
## 快速开始 — 演示模式
```
# 1. 克隆并配置
cp .env.example .env
# 2. 启动所有服务(backend、capture、frontend、prometheus、grafana)
docker compose up --build
# 3. 打开 Dashboard
open http://localhost:5174
# 4. 打开 Grafana(admin / netwatch)
open http://localhost:3000
```
演示模式生成合成的良性流量(约 50 个流/分钟),并定期注入攻击(端口扫描、SYN 洪水、SSH 暴力破解、DNS 洪水)——无需 root 权限或实时网络。
## 快速开始 — 实时捕获模式
```
# 1. 配置以进行实时捕获
cp .env.example .env
# 编辑 .env:设置 DEMO_MODE=false, INTERFACE=
# 2. 启动(capture 服务需要 NET_ADMIN 以使用 raw sockets)
docker compose up --build
# 3. 打开 Dashboard
open http://localhost:5174
```
## 快速开始 — PCAP 重放模式
通过完整的检测管道重放录制的 `.pcap` / `.pcapng` 文件:
```
# 1. 配置
cp .env.example .env
# 编辑 .env:
# DEMO_MODE=false
# REPLAY_PCAP=/data/your-capture.pcap
# REPLAY_SPEED=10.0 (10倍实时速度;0 = 尽可能快)
# REPLAY_LOOP=true (循环以进行持续演示)
# 2. 将你的 PCAP 挂载到 docker-compose.yml 中的 capture 容器里:
# volumes:
# - ./your-capture.pcap:/data/your-capture.pcap
# 3. 启动
docker compose up --build
```
PCAP 重放遵循真实的包间时间(由 `REPLAY_SPEED` 缩放),因此检测管道可以看到真实的流持续时间和到达间隔统计信息。
## 训练 ML 模型
ML 阶段是可选的——当模型不存在时,系统仅使用统计检测运行。要启用 ML 分类:
```
# 1. 下载 CIC-IDS-2018(说明请参阅 data/README.md)
# 将 CSV 文件放置在 data/ 目录中
# 2. 训练模型
cd backend
pip install -r requirements.txt
python3 -m ml.train
# 3. 评估
python3 -m ml.evaluate
# 4. 模型将保存到 backend/ml/models/ 并在启动时自动加载
```
## 运行测试
```
cd backend
pip install pytest pytest-asyncio httpx
python3 -m pytest tests/ -v
```
跨 6 个文件的 50 个测试:
| 文件 | 涵盖范围 |
|---|---|
| `test_stage1.py` | 滚动基线 z-score 检测、预热、严重性阈值、异常分类 |
| `test_stage2.py` | ML 分类器加载、预测、置信度门控、类别→严重性映射 |
| `test_severity.py` | 严重性组合逻辑、阶段合并、未知异常回退处理 |
| `test_pipeline.py` | 警报速率限制和去重 |
| `test_models.py` | 数据库插入/查询、分页、按严重性/类别/IP 筛选 |
| `test_api.py` | REST 端点响应、认证令牌强制执行、CSV 导出、统计端点 |
## 性能指标
在来自 CIC-IDS-2018 数据集的 **4,089,895 个流**上进行训练(80/20 的训练/测试拆分):
### Random Forest (有监督多分类)
| 指标 | 值 |
|---|---|
| 总体准确率 | **90.91%** |
| 加权 F1 分数 | **0.91** |
| 良性误报率 | **3.21%** |
按类别细分:
| 类别 | 精确率 | 召回率 | F1 |
|---|---|---|---|
| Benign | 1.00 | 0.97 | 0.98 |
| DDoS | 0.72 | 0.94 | 0.82 |
| DoS | 0.78 | 0.63 | 0.69 |
### Isolation Forest (无监督异常检测)
| 指标 | 值 |
|---|---|
| 误报率 | **0.96%** |
| 检出率 | 0.19%(预期值——仅在良性基线上训练) |
## 环境变量
### 后端
| 变量 | 默认值 | 描述 |
|---|---|---|
| `CAPTURE_TOKEN` | `change-me-in-production` | 捕获和后端之间的共享认证令牌 |
| `ML_MODELS_PATH` | `./ml/models` | 训练好的模型文件的路径 |
| `LOG_LEVEL` | `INFO` | 日志详细程度 |
| `STAT_THRESHOLD` | `3.5` | 统计异常的 Z-score 阈值 |
| `ROLLING_WINDOW_SIZE` | `1000` | 滚动基线窗口中的流数量 |
| `STAT_WARMUP` | `30` | 统计检测激活前的最少样本数 |
| `SEVERITY_MEDIUM_THRESHOLD` | `3` | 中等 (MEDIUM) 严重性的异常特征数量 |
| `SEVERITY_HIGH_THRESHOLD` | `6` | 高 (HIGH) 严重性的异常特征数量 |
| `IF_THRESHOLD` | `-0.2` | Isolation Forest 异常分数截止点 |
| `RF_CONFIDENCE_THRESHOLD` | `0.4` | 信任分类的最低 RF 概率 |
| `ALERT_RATE_LIMIT_SECONDS` | `10` | 在此窗口内抑制重复的 (src_ip + category) 警报 |
| `ABUSEIPDB_API_KEY` | _(空)_ | 可选 — 在威胁情报中启用 AbuseIPDB 置信度评分 |
### 捕获服务
| 变量 | 默认值 | 描述 |
|---|---|---|
| `DEMO_MODE` | `true` | 启用合成流量生成 |
| `REPLAY_PCAP` | _(空)_ | 用于重放模式的 PCAP 文件路径(优先于演示模式) |
| `REPLAY_SPEED` | `10.0` | 重放速度乘数(1 = 实时,0 = 最快速度) |
| `REPLAY_LOOP` | `false` | 连续循环 PCAP 文件 |
| `INTERFACE` | `eth0` | 用于实时捕获的网络接口 |
| `BPF_FILTER` | `ip` | 传递给 Scapy 的 BPF 过滤器表达式 |
| `FLOW_TIMEOUT` | `120` | 空闲流过期并发出前的秒数 |
| `MAX_FLOW_PACKETS` | `10000` | 强制发出前每个流的最大数据包数 |
### 前端
| 变量 | 默认值 | 描述 |
|---|---|---|
| `VITE_API_URL` | `http://localhost:8001` | 后端 REST API 基础 URL |
| `VITE_WS_URL` | `ws://localhost:8001` | 后端 WebSocket 基础 URL |
## 服务端口
| 服务 | 主机端口 | 备注 |
|---|---|---|
| 后端 | **8001** | 内部端口 8000 |
| 前端 | **5174** | 内部端口 5173 |
| Prometheus (Prometheus) | **9090** | |
| Grafana | **3000** | 登录凭据:`admin` / `netwatch` |
## API 参考
| 方法 | 端点 | 描述 |
|---|---|---|
| `POST` | `/ingest` | 从捕获服务接收流(需要 `X-Capture-Token`) |
| `GET` | `/alerts` | 分页的警报历史——筛选条件:`severity`、`category`、`src_ip`、`since`、`until`、`limit`、`offset` |
| `GET` | `/alerts/recent` | 最近 N 条警报 |
| `GET` | `/alerts/export` | 带可选筛选条件(`severity`、`category`、`src_ip`、`until`)的 CSV 导出 |
| `GET` | `/stats/summary` | 仪表板摘要统计 |
| `GET` | `/stats/timeline` | 按分钟分桶的流量/警报时间线 |
| `WS` | `/ws/alerts` | 实时警报 + 统计流(JSON、`alert` 和 `stats_update` 消息类型) |
| `GET` | `/threats/intel/{ip}` | 针对某个 IP 地址的 GeoIP + AbuseIPDB 威胁情报 |
| `GET` | `/health` | 服务健康检查——ML 加载状态、运行时间、已处理流 |
| `GET` | `/metrics` | Prometheus 抓取端点 |
## 项目结构
```
netwatch/
├── docker-compose.yml # Orchestrates all 5 services
├── .env.example # Environment configuration template
│
├── capture/ # Packet capture + flow engine
│ ├── main.py # Entrypoint: demo / live capture / PCAP replay
│ ├── capture.py # Scapy live sniffer (BPF filter + SIGTERM)
│ ├── flow_engine.py # 5-tuple flow assembly (bounded to 50K flows)
│ ├── features.py # 20-dimension feature extraction
│ ├── publisher.py # Async HTTP publisher (background queue, non-blocking)
│ ├── demo_traffic.py # Synthetic traffic + attack pattern injection
│ └── pcap_replay.py # PCAP replay with speed multiplier + optional loop
│
├── backend/ # FastAPI backend
│ ├── main.py # App entrypoint + lifespan + /health + /metrics
│ ├── config.py # All settings via pydantic-settings + env vars
│ ├── database.py # SQLite async with WAL mode
│ ├── metrics.py # Prometheus counters / gauges / histogram
│ ├── enrichment.py # IP threat intelligence (GeoIP + AbuseIPDB, LRU cache)
│ ├── models/alert.py # DB operations: insert, query, paginate, filter
│ ├── schemas/ # Pydantic schemas (FlowData, AlertOut)
│ ├── routers/
│ │ ├── ingest.py # POST /ingest — flow ingestion
│ │ ├── alerts.py # GET /alerts, /alerts/recent, /alerts/export
│ │ ├── ws.py # WS /ws/alerts — live streaming
│ │ └── threats.py # GET /threats/intel/{ip}
│ ├── detection/
│ │ ├── pipeline.py # Two-stage orchestrator + alert rate limiter
│ │ ├── stage1_statistical.py # Z-score rolling baseline
│ │ ├── stage2_ml.py # IF + RF with confidence gating
│ │ └── severity.py # Severity scoring + stage combination logic
│ ├── ml/
│ │ ├── train.py # Train on CIC-IDS-2018
│ │ ├── evaluate.py # Compute and print metrics
│ │ └── preprocess.py # Column alignment + label simplification
│ └── tests/ # pytest test suite (50 tests)
│ ├── conftest.py
│ ├── test_stage1.py
│ ├── test_stage2.py
│ ├── test_severity.py
│ ├── test_pipeline.py
│ ├── test_models.py
│ └── test_api.py
│
├── frontend/ # React + TypeScript dashboard
│ ├── src/
│ │ ├── api/client.ts # Axios instance (reads VITE_API_URL)
│ │ ├── hooks/
│ │ │ ├── useAlertStream.ts # WebSocket hook with reconnect backoff
│ │ │ └── useStats.ts # Polling hook (summary + timeline, loading state)
│ │ ├── pages/Dashboard.tsx # Main layout — modal state, filters, tab state
│ │ └── components/
│ │ ├── AlertFeed.tsx # Live scrollable alert list + expand/collapse
│ │ ├── AlertToolbar.tsx # Severity filter buttons, IP search, CSV export
│ │ ├── AlertDetailModal.tsx # Forensic modal: flow metadata, z-score chips,
│ │ │ # ML details, IP threat intel, related alerts
│ │ ├── StatsBar.tsx # Summary cards (flows, alerts, rate-limited, ML)
│ │ │ # + inline sparkline charts
│ │ ├── TrafficChart.tsx # Area chart with gradient fills + legend
│ │ ├── ProtocolBreakdown.tsx # Protocol/category pie chart
│ │ ├── ThreatHeatmap.tsx # Attack category bar chart with gradient fill
│ │ ├── SeverityBadge.tsx # Severity chip — CRITICAL pulses with red glow
│ │ ├── CriticalAlertToast.tsx # Fixed top-right toasts for CRITICAL alerts
│ │ ├── ErrorBoundary.tsx # React error boundary with dark fallback UI
│ │ └── Skeleton.tsx # Shimmer loading placeholders
│ └── index.html
│
├── infra/
│ ├── prometheus/
│ │ └── prometheus.yml # Scrape config: backend:8000/metrics every 10s
│ └── grafana/
│ ├── provisioning/
│ │ ├── datasources/prometheus.yml
│ │ └── dashboards/dashboards.yml
│ └── dashboards/
│ └── netwatch.json # Pre-built Grafana dashboard
│
└── data/ # CIC-IDS-2018 CSV files (gitignored)
└── README.md # Dataset download instructions
```
## 20 维特征向量
每个网络流都表示为一个固定长度的数值向量——这是 ML 阶段和统计基线的相同输入:
| # | 特征 | 描述 |
|---|---|---|
| 1 | `duration` | 流持续时间(秒) |
| 2 | `total_fwd_packets` | 转发包数量 |
| 3 | `total_bwd_packets` | 后向包数量 |
| 4 | `total_fwd_bytes` | 转发字节数量 |
| 5 | `total_bwd_bytes` | 后向字节数量 |
| 6 | `fwd_packet_rate` | 每秒转发包数 |
| 7 | `bwd_packet_rate` | 每秒后向包数 |
| 8 | `fwd_byte_rate` | 每秒转发字节数 |
| 9 | `bwd_byte_rate` | 每秒后向字节数 |
| 10 | `mean_iat_fwd` | 平均到达时间间隔(转发) |
| 11 | `std_iat_fwd` | 到达时间间隔标准差(转发) |
| 12 | `mean_iat_bwd` | 平均到达时间间隔(后向) |
| 13 | `std_iat_bwd` | 到达时间间隔标准差(后向) |
| 14 | `syn_flag_count` | TCP SYN 标志 |
| 15 | `ack_flag_count | TCP ACK 标志 |
| 16 | `fin_flag_count` | TCP FIN 标志 |
| 17 | `rst_flag_count` | TCP RST 标志 |
| 18 | `psh_flag_count` | TCP PSH 标志 |
| 19 | `mean_packet_length` | 平均数据包大小(字节) |
| 20 | `std_packet_length` | 数据包大小的标准差 |
## 许可证
MIT
标签:Apex, API集成, C2通信检测, CIC-IDS-2018, CISA项目, DoS攻击检测, Grafana, IP 地址批量处理, NIDS, WebSocket, 依赖分析, 免杀技术, 入侵检测系统, 可观测性, 威胁情报, 孤立森林, 安全数据湖, 容器化, 开发者工具, 插件系统, 数据流处理, 暴力破解检测, 机器学习, 深度学习, 特征工程, 端口扫描检测, 统计基线, 网络安全, 网络异常检测, 自定义请求头, 请求拦截, 逆向工具, 随机森林, 隐私保护, 零日攻击防御