Karan-1708/SentinelAI---Autonomous-Threat-Intelligence-Incident-Response-Platform
GitHub: Karan-1708/SentinelAI---Autonomous-Threat-Intelligence-Incident-Response-Platform
SentinelAI 是一个自主威胁情报与事件响应平台,通过两阶段 ML 推理对日志进行异常检测与威胁分类,并生成附带补救步骤的可解释事件报告,充当自动化 Tier-1 SOC 分析师。
Stars: 0 | Forks: 0
# SentinelAI — 代码库指南
## 项目概述
自主威胁情报与事件响应平台。充当 Tier-1 SOC 分析师:
摄入日志 → 检测异常 → 分类威胁 → 映射至 MITRE ATT&CK → 生成
包含补救 playbook 的可解释事件报告。
**目标受众**:面向 SOC/安全工程岗位(Splunk、CrowdStrike、
Microsoft Sentinel)的代表作。ISO27001 背景强调了为何在受监管行业中 SHAP 可解释性至关重要。
## 架构
```
Browser (https) ─┐
│
Logs → ELK (Logstash → Elasticsearch) ┐
├─ nginx (TLS + CSP)
│ │
│ ├─ https → FastAPI (/api, JWT)
│ │ → IsolationForest + XGBoost
│ │ → MITRE ATT&CK mapping
│ │ → SHAP explanation
│ │ → PostgreSQL (Incident)
│ └─ wss → WebSocket feed (JWT-authed)
└─ static → React 18 dashboard (zod-validated)
```
两阶段 ML 推理:
1. **IsolationForest**(仅在 BENIGN 数据上训练):标记异常,捕获 zero-day 攻击
2. **XGBoost**(监督多分类):对已知攻击类型进行标记(DDoS、PortScan 等)
如果 IsolationForest 返回“normal”,则跳过 XGBoost(为保证性能提前退出)。在运行 `joblib.load` 之前,每个模型 artifact 都会针对 `MODEL_MANIFEST_PATH` 进行 SHA-256 验证 —— 模型文件被视为不受信任的输入。
## 关键目录
| 目录 | 用途 |
|-----------|---------|
| `ingestion/` | CICIDS-2017 标准化,ES 批量索引器,合成日志生成器 |
| `models/` | sklearn 预处理器,IsolationForest,XGBoost,MITRE 映射器,MLflow 训练器 |
| `explainability/` | SHAP TreeExplainer,ReportLab PDF 报告生成器 |
| `api/` | FastAPI 异步后端 —— 摄入 / 预测 / 事件 / 报告 / WebSocket |
| `api/auth/` | JWT + argon2id 认证模块及 FastAPI 依赖 |
| `dashboard/` | React 18 + Vite + Tailwind —— 实时 SOC dashboard |
| `dashboard/src/schemas/` | 对每个服务器 payload 进行 zod 运行时验证 |
| `docker/` | 特定于服务的配置(logstash pipeline、kibana.yml、nginx.conf、TLS) |
| `data/` | 数据集下载脚本 + SHA-256 清单;原始数据被 gitignore |
| `notebooks/` | EDA、特征选择、模型实验、SHAP 分析 |
| `requirements/` | 按关注点拆分的固定 Python 依赖(base/ml/api/dev) |
| `scripts/` | 用于训练、数据库填充、开发证书生成的 CLI 入口点 |
| `tests/integration/` | 需要完整 Docker 环境的端到端测试 |
| `.github/workflows/` | GitHub Actions CI(ruff、bandit、pip-audit、pytest、vitest、build) |
## 本地运行
### 前置条件
- **Docker Desktop** ≥ 4.x(Windows / macOS / Linux),推荐 8 GB 内存
- **Git**
- PATH 中需包含 **openssl**(用于生成开发 TLS 证书和密钥)
无需本地安装 Python —— 一切均在 Docker 内运行。
### 步骤 1 — 克隆并配置环境
```
git clone https://github.com/Karan-1708/SentinelAI.git
cd SentinelAI
# Windows
copy .env.example .env
# macOS / Linux
cp .env.example .env
```
打开 `.env` 并为每个 `REPLACE_ME_*` 占位符生成一个新的密钥:
```
# 32 字节高熵随机数据 — 每个 secret 运行一次
openssl rand -hex 32
```
如果缺少任何必需的密钥或仍保留占位符值,API 将拒绝在 `staging` 或 `production` 环境中启动(`api/config.py` —— `model_validator` 会强制执行此操作)。
### 步骤 1.5 — 为内部面板引导开发 TLS + basic-auth
```
bash scripts/gen_dev_certs.sh
```
幂等操作。写入:
- `docker/nginx/certs/server.crt` + `server.key` —— 用于 `sentinelai.local` /
`localhost` 的自签名证书。Nginx 在 443 端口通过 HTTPS 提供 dashboard 和 `/api` 服务。
- `docker/nginx/htpasswd` —— 保护 `/mlflow` 和
`/kibana` 的开发凭据(`admin` / `dev`)。在部署前请务必替换。
这两个路径均被 gitignore。
### 步骤 2 — 启动完整的开发栈
```
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
```
这将启动 9 个服务。**Elasticsearch 需要 60–90 秒**才能通过健康检查。
在继续操作之前,请等待其变为健康状态:
```
docker inspect --format="{{.State.Health.Status}}" sentinelai-elasticsearch-1
# 持续运行直到 output 为:healthy
```
### 步骤 3 — 一次性操作:设置 kibana_system 密码
首次启动时必须执行此操作,以便 Kibana 能够向 Elasticsearch 进行身份验证。后续启动可跳过 —— `esdata` 卷会将其持久化。
```
docker compose exec elasticsearch bash -c '
curl -s -X POST -u "elastic:${ELASTIC_PASSWORD}" \
-H "Content-Type: application/json" \
https://localhost:9200/_security/user/kibana_system/_password \
--cacert /usr/share/elasticsearch/config/certs/ca/ca.crt \
-d "{\"password\":\"${KIBANA_PASSWORD}\"}"
'
```
预期响应:`{}`
### 步骤 4 — 填充初始管理员用户
系统没有开放的自注册功能 —— 用户配置由管理员控制。直接在数据库中创建第一个管理员:
```
docker exec -it sentinelai-api-1 `
python scripts/seed_postgres.py --admin analyst@example.com
```
`seed_postgres.py` 从 stdin 读取密码(绝不回显、绝不记录、绝不作为命令行参数)。它会验证数据库连接,以幂等方式创建表,然后插入管理员。重新运行是安全的 —— 现有的电子邮件将保持不变。
### 步骤 5 — 训练模型
训练在 API 容器内运行(Python 3.12、sklearn 1.5.2、XGBoost 2.0.3)。
**选项 A —— 合成样本(速度快,约 30 秒,适合测试)**
```
# Windows
docker cp data\sample\cicids_sample.csv sentinelai-api-1:/tmp/cicids_sample.csv
# macOS / Linux
docker cp data/sample/cicids_sample.csv sentinelai-api-1:/tmp/cicids_sample.csv
docker exec -u root sentinelai-api-1 python -m models.trainer `
--data-dir /tmp --model-dir /models --max-rows 1000 `
--mlflow-uri http://mlflow:5000
```
**选项 B —— 真实 CICIDS-2017 数据集(约 8 GB 下载量,准确率最高)**
```
# 首次运行:bootstrap SHA-256 manifest(需要受信任的网络)。
docker exec sentinelai-api-1 python data/download_cicids.py --skip-hash-check
# 然后提交生成的 data/cicids_sha256.txt,以便验证未来的每次 download。
docker exec -u root sentinelai-api-1 python -m models.trainer `
--data-dir data/cicids --model-dir /models `
--mlflow-uri http://mlflow:5000
```
训练器会在每个模型 artifact(SHA-256、sklearn /
xgboost 版本、类列表、trained_at)旁边写入一个配套的 `manifest.json`。将 `.env` 中的 `MODEL_MANIFEST_PATH` 指向它,以便 API 在启动时验证每个 artifact。
训练完成后,修复模型文件所有权并重启 API:
```
docker exec -u root sentinelai-api-1 chown -R appuser:appuser /models
docker compose -f docker-compose.yml -f docker-compose.dev.yml restart api
```
### 步骤 6 — 验证一切是否正常
每个修改型 endpoint 都需要 bearer token。基于 nginx 的流程:
```
# 1. 登录并捕获 JWT
$login = curl -s -k -X POST https://localhost/api/auth/login `
-H "Content-Type: application/x-www-form-urlencoded" `
--data "username=analyst@example.com&password="
$token = ($login | ConvertFrom-Json).access_token
# 2. Health check(设计上为 unauthenticated)
curl -k https://localhost/api/health
# 预期:{"status":"ok","database":"ok","prediction_service":"ready"}
# 3. 测试一个 prediction(authenticated)
curl -k -X POST https://localhost/api/predict `
-H "Content-Type: application/json" `
-H "Authorization: Bearer $token" `
--data-binary "@scripts/test_payload.json"
# 预期:threat_label "DDoS", mitre_techniques [T1498, T1499], top_shap_features [...]
```
打开 **https://localhost/** —— React dashboard 会加载登录界面。使用在步骤 4 中创建的管理员凭据登录,实时事件流将通过 `wss://` 传输。
### 服务 URL(开发模式)
| 服务 | URL | 凭据 |
|---------|-----|-------------|
| React dashboard | https://localhost/ | 步骤 4 中创建的 admin |
| FastAPI(通过 nginx) | https://localhost/api/ | 来自 `/api/auth/login` 的 JWT |
| FastAPI(直接开发) | http://localhost:8000 | JWT(无 TLS —— 仅限开发) |
| Vite 开发服务器 | http://localhost:3000 | — (代理 `/api` 和 `/ws`) |
| MLflow UI | https://localhost/mlflow/ | `admin` / `dev` (htpasswd) |
| Kibana | https://localhost/kibana/ | `admin` / `dev` (htpasswd) |
| MinIO console | http://localhost:9001 | .env 中的 `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` |
| Elasticsearch | https://localhost:9200 | .env 中的 `elastic` / `ELASTIC_PASSWORD` |
| PostgreSQL | localhost:5432 | .env 中的 `sentinel` / `POSTGRES_PASSWORD` |
### 停止运行环境
```
# 停止所有 containers(保留 volumes)
docker compose -f docker-compose.yml -f docker-compose.dev.yml down
# Full reset — 同时删除所有 data volumes
docker compose -f docker-compose.yml -f docker-compose.dev.yml down -v
```
## 身份验证模型
- **角色**:`viewer` < `analyst` < `admin`(层级定义在 `api/auth/dependencies.py` 中)。
- **令牌**:HS256 JWT,默认 TTL 为 30 分钟,使用 `API_SECRET_KEY` 签名。声明包含
`sub`(用户 UUID)、`role`、`iss`、`aud`、`iat`、`exp`。
- **密码哈希**:通过 `argon2-cffi` 使用 Argon2id。对于未知的电子邮件,`/auth/login` 会针对一个虚拟哈希进行验证,以消除否则会暴露哪些电子邮件存在的计时侧信道。
- **速率限制**:SlowAPI 全局限制器(默认 120次/分钟)。`/auth/login` 限制为每个 IP 5次/分钟;`/predict` 和 `/ingest` 为 60次/分钟;`/reports/{id}` 为 30次/分钟。
- **WebSocket**:`wss:///ws/feed?token=` —— 需要 token;服务器还会针对 `CORS_ORIGINS` 验证 `Origin`(CSWSH 防御)。token 无效 → 关闭代码 4401;origin 无效 →
4403;服务器满载 → 4408。
- **Dashboard token 存储**:内存中(Zustand)。不使用 `localStorage` —— 否则,应用上的 XSS 会窃取长效 token。代价是刷新标签页时需要进行一次登录往返。
## 安全态势
目前已实施的控制措施概览:
- **传输**:nginx 终止 TLS 1.2 / 1.3;HTTP → HTTPS 重定向;HSTS `max-age=63072000`。
- **头部**:严格的 CSP,`X-Frame-Options: DENY`,`X-Content-Type-Options: nosniff`,
`Referrer-Policy: strict-origin-when-cross-origin`,`Permissions-Policy` 拒绝摄像头 / 麦克风 /
地理位置。
- **认证**:在每个 HTTP + WS 路由上使用 JWT bearer;角色层级;仅限管理员的注册。
- **CORS**:明确的 origin 允许列表;明确的方法 + 头部允许列表(无 `*`)。
- **速率限制**:SlowAPI,基于路由。
- **输入验证**:Pydantic v2 字段验证器限制 features 字典大小(256 个条目),IP
地址通过 `IPvAnyAddress` 解析,值必须有限且有界(`|x| ≤ 1e12`)。
- **模型完整性**:在每次执行 `joblib.load` /
`xgb.Booster.load_model` 之前进行 SHA-256 清单验证。生产环境中若无清单则拒绝加载。
- **PDF 安全**:每个受用户影响的字符串均通过 `xml.sax.saxutils.escape` 进行转义;IP 通过
`ipaddress` 验证;MITRE URL 进行协议检查。移除了通配的 `except` 捕获 —— 渲染失败将抛出 `ReportRenderError`。
- **Dashboard**:zod schema 验证每个 REST + WS payload;`safeHttpUrl` 会在渲染为 `href` 之前拒绝 `javascript:` / `data:`
协议;所有路由均围绕 `ErrorBoundary`。
- **容器**:API 以 `read_only: true`、`cap_drop: ALL`、`no-new-privileges` 运行。
- **错误**:全局异常处理程序仅发出通用的 `detail` + 请求 ID;traceback 保留在服务器日志中。
- **数据集**:CICIDS 下载器流式传输至 `.partial` 附属文件,针对
`data/cicids_sha256.txt` 进行 SHA-256 验证,使用指数退避重试,规范化文件名以防范 zip-slip 攻击。
完整披露政策:[SECURITY.md](SECURITY.md)。
## 测试
```
# Python — 跨 API、models、ingestion 的 44 个测试
pytest api/tests models/tests ingestion/tests -q
# Dashboard — 针对 zod schemas + URL guard 的 vitest suites
npm --prefix dashboard run test
```
CI(`.github/workflows/ci.yml`)在每次推送和 pull request 时运行:
- 针对需求执行 `ruff check`、`mypy`(建议性)、`bandit -r`、`pip-audit --strict`
- 针对 Python 表面执行 `pytest -q --cov`
- 针对 dashboard 执行 `npm run test` + `npm run build`
仓库根目录下的 `conftest.py` 设置了 `random.seed(0)` 和 `np.random.seed(0)` autouse,因此无论运行顺序如何,每个测试都是确定性的。
## 关键文件
- `docker-compose.yml` —— 整个服务图表;ELK TLS 证书引导必须首先成功
- `docker/nginx/nginx.conf` —— TLS 终止、CSP、HSTS、安全头部;单一外部 ingress
- `api/main.py` —— FastAPI 生命周期仅加载一次 ML 模型;全局异常处理程序;SlowAPI middleware
- `api/auth/security.py` —— JWT 创建 / 解码 + argon2id 密码辅助工具
- `api/services/prediction_service.py` —— 反序列化前的 SHA-256 清单验证
- `ingestion/normalizer.py` —— CICIDS-2017 前导空格表头、Infinity 值、精细与粗糙标签映射
- `models/threat_classifier.py` —— 未见标签过滤器、确定性编码器路径、清单附属文件
- `explainability/report_generator.py` —— 带有 `xml.sax.saxutils.escape` 的 Platypus PDF,用于每个用户字段
- `dashboard/src/schemas/incident.ts` —— zod schema + `safeHttpUrl` 守卫
## 已知陷阱
- **CICIDS-2017 标头**:所有列名都有导空格(` Label`、` Flow Duration`)。
`normalizer.py` 使用 `df.columns.str.strip()` 去除它们。
- **CICIDS-2017 Infinity 值**:`Flow Bytes/s` 和 `Flow Packets/s` 包含 `Infinity`。
替换为 `np.nan`,然后使用列中位数进行插补。
- **numpy 固定版本**:SHAP 0.45.x 需要 `numpy<2.0`。固定为 `numpy==1.26.4`。
- **XGBoost class_weight**:XGBoost 不接受 `class_weight='balanced'`。使用
`compute_class_weight('balanced', ...)` 并将结果作为 `sample_weight` 传递给 `.fit()`。
- **IsolationForest 训练数据**:仅在 BENIGN 行上进行训练。在所有类上进行训练会破坏正态分布基线。
- **ELK 8.x TLS**:ELK 8 默认启用了安全性。`setup` 服务会在 ES 启动之前将 TLS 证书引导至 `certs` Docker 卷中。证书目录权限必须为 `755`(而不是 `750`),以便 Logstash 能够读取它们。
- **SHAP 多分类形状**:`TreeExplainer.shap_values(X)` 在不同 SHAP 版本中返回的形状不同。
`shap_explainer.py` 会直接向模型询问获胜类,而不是根据 SHAP 总和进行猜测。
- **MLflow 预处理器**:`mlflow.xgboost.autolog()` 会记录 XGBoost 模型,但不会记录 sklearn 预处理器。需手动记录:`mlflow.log_artifact("models/preprocessor.joblib")`。
- **sklearn 版本锁定**:sklearn 1.6+ 添加了 XGBoost 2.0.x 未实现的 `__sklearn_tags__` 协议。固定为 `scikit-learn==1.5.2`。
- **setuptools 固定版本**:setuptools 82+ 移除了 MLflow 2.13.0 所需的 `pkg_resources`。
固定为 `setuptools<82`。
- **模型所有权**:模型由 root(训练)写入,但 API 以 `appuser` 身份运行。
训练后,在容器内运行 `chown -R appuser:appuser /models`。
- **需要 openssl**:`scripts/gen_dev_certs.sh` 需要 PATH 中包含 `openssl`。
- **生产环境中需要模型清单**:在 `APP_ENV=production` 时未设置 `MODEL_MANIFEST_PATH`
是致命的 —— API 不会反序列化未经验证的模型文件。
- **CICIDS 下载器默认严格要求**:首次下载需要
`--skip-hash-check`,之后应填充并提交 `data/cicids_sha256.txt`,以便每次后续运行时进行验证。
## 技术栈版本
**运行时**
- Python 3.12 (Docker)
- Node 24 (Docker)
- ELK 8.17.0
- XGBoost 2.0.3 + scikit-learn 1.5.2
- FastAPI 0.111.0
- React 18、Vite 5、TypeScript 5
- PostgreSQL 16
- MLflow 2.13.0
- MinIO (最新版)
**安全技术栈**
- pyjwt 2.9.0(HS256 签名)
- argon2-cffi 23.1.0(密码哈希)
- slowapi 0.1.9(速率限制)
- zod 3.23.8(dashboard 运行时验证)
- aiosqlite 0.20.0(仅限开发测试)
标签:AMSI绕过, Apex, ATT&CK框架, AV绕过, FastAPI, React, SOC分析师, Syscalls, 内容过滤, 威胁检测, 安全运营, 扫描框架, 机器学习, 测试用例, 请求拦截, 越狱测试, 逆向工具