RISHITASHARMA01/sentinelhub

GitHub: RISHITASHARMA01/sentinelhub

一个自建的安全运营中心平台,实现了多源日志接入、MITRE ATT&CK 映射检测、威胁情报富化和实时可视化 Dashboard 的完整 SIEM 流程。

Stars: 0 | Forks: 0

# SentinelHub — 自建的 SOC 平台 [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) SentinelHub 会收集安全相关的日志(SSH 认证日志、Web 服务器日志),将它们统一规范化为通用 schema,执行映射到 MITRE ATT&CK 的检测规则,利用威胁情报对检测结果进行丰富化,并通过实时 dashboard 将所有信息展示出来——这相当于一个从头开始构建的小型 SOC SIEM 工具。 项目采用分阶段构建,每个阶段都可以独立运行和测试——请参阅[项目状态](#project-status)。 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/RISHITASHARMA01/sentinelhub/actions/workflows/ci.yml) ## 截图 | 概览 | 告警(展开) | 日志 | |---|---|---| | ![概览](https://static.pigsec.cn/wp-content/uploads/repos/cas/f2/f29b6c38edfa18d8c89a48176cb3bf9abd7babab70dd46099f7b0f22020c69b9.png) | ![告警展开](https://static.pigsec.cn/wp-content/uploads/repos/cas/11/11eab58b26485e62f737aba39cfc392ef58bbbe297e160648e37513bbc2006a0.png) | ![日志](https://static.pigsec.cn/wp-content/uploads/repos/cas/ca/caf433a8b9b33c7b03d80896896dc152599b7e63f9f9872c12ac5bcd6bee7c85.png) | ## 架构 ``` Raw logs (SSH, nginx, honeypot) │ ▼ Log Parser (app/services/log_parser.py) - regex-based normalization per source type │ ▼ Ingestion API (app/api/ingestion.py) - POST /ingest/line (single line, for streaming agents) - POST /ingest/file (bulk upload, for testing/backfill) │ ▼ PostgreSQL (LogEvent table) │ ├────────────────────────────┐ ▼ ▼ Query API (app/api/logs.py) Detection Engine (app/services/detection_engine.py) - GET /logs/ - rule-based analysis of unprocessed LogEvents - GET /logs/stats/summary - sliding-window burst detection per src_ip - maps findings to MITRE ATT&CK technique IDs │ ▼ PostgreSQL (Alert table) │ ▼ Detection + Alerts API - POST /detect/run (manual trigger) - GET /alerts/ (filter + paginate) - GET /alerts/{id} ``` ### 检测规则(第 2 阶段) | 规则 | MITRE 技术 | 触发条件 | |---|---|---| | `brute_force_login` | T1110 (Brute Force) | 60 秒内同一 IP 发生 5 次以上失败登录 | | `credential_stuffing` | T1110 (Brute Force) | 同上,但爆发涉及 5 个以上不同的用户名——标记为 `high` 严重性而非 `medium` | | `web_path_scanning` | T1595 (Active Scanning) | 60 秒内同一 IP 对已知攻击路径(`/wp-login.php`、`/.env`、`/admin` 等)发起 8 次以上请求或触发 404 | | `off_hours_login` | T1078 (Valid Accounts) | 00:00–05:00 之间的*成功*登录——低严重性/信息提示 | 阈值和时间窗口以常量的形式定义在 `detection_engine.py` 的开头,方便进行调整(也方便在面试中具体指出)。 ### 威胁情报丰富化(第 3 阶段) 当检测引擎创建告警时,会自动通过 **AbuseIPDB** 的免费声誉 API(`backend/app/services/threat_intel.py`)查询攻击源 `src_ip`,并将结果(滥用置信度分数、国家、ISP、总报告数)存储在 `Alert.enrichment` 中。 ``` Detection Engine creates an Alert │ ▼ threat_intel.get_ip_reputation(src_ip) - in-memory cache check (1hr TTL) ──► cache hit? return cached data │ cache miss ▼ AbuseIPDB API ──(no key / network error)──► log warning, return None │ success ▼ Alert.enrichment (JSONB) ``` 设计说明: - **未配置 API key?** 跳过丰富化并记录一条警告日志——无论是否配置,检测和告警都会正常工作。威胁情报是附加功能,并非硬性依赖。 - **缓存**:使用简单的内存字典 `{ip: (timestamp, data)}` 并设置 1 小时的 TTL,这样如果一个多次违规的 IP 触发了多个告警,就不会因为每次重新检查而耗尽免费套餐的每日配额。 - **手动重新丰富化**:`POST /alerts/{id}/enrich` 会针对单个告警重新运行查询——适用于在配置 key 之前创建的告警,或用于强制进行超过 cache TTL 的最新检查。 #### 获取免费的 AbuseIPDB API key 1. 在 https://www.abuseipdb.com/register 注册(免费套餐即可)。 2. 从 https://www.abuseipdb.com/account/api 获取你的 API key。 3. 将 `.env.example` 复制为 `.env`(与 `docker-compose.yml` 在同一目录下),并设置 `ABUSEIPDB_API_KEY=`。 4. 重启后端:`docker compose up -d`(compose 会自动读取 `.env` 进行变量替换)。 ``` cp .env.example .env # 编辑 .env,然后: docker compose up -d curl -X POST http://localhost:8001/detect/run curl "http://localhost:8001/alerts/" | python3 -m json.tool # enrichment should now be populated ``` ### Dashboard(第 4 阶段) `frontend/` 中有一个基于 React + Vite + Tailwind 的 dashboard,其风格被设计为深色 SOC 控制台(类似 Splunk/Grafana 的样式),而不是通用的后台管理模板: - **概览** (`/`) —— 总事件数 / 未处理告警数 / 独立攻击者 IP 统计卡片,一个结合了事件与告警的时间序列图表,以及按严重性划分的告警细分,所有图表均通过 Recharts 实现。 - **告警** (`/alerts`) —— 可排序、可进行服务端过滤(严重性 / 状态 / 源 IP)的表格。点击某一行会将其就地展开,显示触发的日志事件、MITRE ATT&CK 信息以及威胁情报丰富化结果。状态下拉菜单会驱动新的 `PATCH /alerts/{id}` endpoint。 - **日志** (`/logs`) —— 可搜索(针对原始日志行进行全文检索)、可过滤、分页的原始 `LogEvent` 行表格。 数据获取被集中管理在 `frontend/src/api/client.js` 中,base URL 可通过 `VITE_API_URL` 进行配置。它由两个新的后端 endpoint 提供支持:`GET /alerts/stats/summary` / `GET /alerts/stats/timeseries` / `GET /logs/stats/timeseries` 用于图表展示,以及 `PATCH /alerts/{id}` 用于状态更改(open → investigating → resolved / false_positive)。 #### 运行 Dashboard ``` docker compose up -d # frontend now included, served on :3001 open http://localhost:3001 ``` 或者在 Docker 之外使用热重载进行本地开发: ``` cd frontend npm install cp .env.example .env # VITE_API_URL defaults to localhost:8001 npm run dev # http://localhost:5173 ``` 后端的 CORS 配置(`backend/app/main.py`)中已经允许了 `http://localhost:3001`(Docker)和 `http://localhost:5173`(Vite dev server)的访问。 第 5 阶段(蜜罐集成)曾是一个可选的延伸目标,在此项目中被跳过——请参阅[项目状态](#project-status)。 ### CI/CD 与部署(第 6 阶段) `.github/workflows/ci.yml` 会在每次 push/PR 时运行:针对真实 Postgres service container 进行后端测试,对后端进行生产级 Docker 构建检查(证明发布的镜像在不含任何开发/测试依赖的情况下能干净构建),以及前端构建检查。 部署指南(Render,免费层):请参阅 **[DEPLOYMENT.md](DEPLOYMENT.md)**。 #### Dockerfile 中的生产规范 - **发布的镜像中不包含开发/测试依赖。** `backend/requirements-dev.txt`(仅包含 `pytest`)只有在 `docker compose` 传递 `INSTALL_DEV=true` 时才会被安装——真正的部署和 CI 的构建检查在构建时都不会包含它。 - **非 root 容器。** 后端以创建的 `appuser`(UID 1000)身份运行;前端使用 `nginxinc/nginx-unprivileged` 而不是普通的 `nginx`,因此其 worker 进程也永远不会以 root 身份运行。 - **精简/多阶段 base 镜像。** 后端使用 `python:3.11-slim`;前端采用多阶段构建(使用 Node 编译,使用 nginx-unprivileged alpine 提供服务),因此 Node/npm 永远不会包含在最终镜像中。 - **可运行时配置的端口。** 后端的 `CMD` 会读取 `$PORT`(本地 Docker Compose 有一个默认的 8000 端口),因为像 Render 这样的 PaaS 提供商会动态分配端口,而不是让你硬编码 8000。 ## 为什么采用这种设计 - **规范化优先**:每个日志源都不同,但检测引擎只需要关注一种 schema(`LogEvent`)。这与真正的 SIEM 工具(Splunk、Elastic)内部使用的模式相同。 - **两条接入路径**:一个基于行的 endpoint 用于实时的 tailing agent,另一个文件上传 endpoint 使你可以使用样本数据(如 `docs/sample_auth.log`)进行批量测试,而无需实时服务器生成日志。 - **基于环境的配置**:DB 凭证来自 `DATABASE_URL`,从不进行硬编码——这是一个基本但重要的安全卫生习惯。 ## 如何在面试中展示该项目 有三个谈论点超越了“它能运行”,以备你被要求深入探讨某个设计决策: 1. **为什么在进行任何检测之前先进行规范化。** SSH 日志、Web 服务器日志以及(未来的)蜜罐 JSON 在网络传输中的表现完全不同。`log_parser.py` 预先将每个来源转换为统一的 `LogEvent` 结构,因此 `detection_engine.py` 无需知道或关心事件的来源——它只需判断“是否在 60 秒内发生了来自同一 IP 的过多 `auth_failure` 事件?”。以后添加新的日志源无需修改任何检测代码;你只需要编写一个新的解析器函数。 2. **为什么将发现映射到 MITRE ATT&CK 而不是自己发明标签。** MITRE ATT&CK 是业界通用的攻击行为词汇表——一个真正的 SOC 告警写着“T1110”,在任何地方代表的含义都是一样的,就像 HTTP 404 在任何地方代表的含义都相同一样。在这里使用它虽然是件小事,但它表明我了解真实安全团队是如何沟通发现的,而不仅仅是知道如何写 regex。 3. **基于规则的检测 vs. 机器学习(ML)——以及我为什么从规则开始。** 这里的每个告警都可以追溯到一个明确、易读的条件(`60` 秒内 `BRUTE_FORCE_THRESHOLD = 5` 次失败登录)——你可以指出触发告警的确切代码行,并用一句话向非技术背景的利益相关者进行解释。ML 异常检测器可以捕捉到人类没有明确编写代码的攻击模式,但这牺牲了可解释性,并且需要标注过的训练数据和调优,以避免让分析师淹没在误报中。正是因为这个原因,真实的 SOC 通常从规则(Sigma 规则、Splunk 关联搜索)开始,然后再在此基础上叠加 ML 来捕获规则无法捕捉的模式。 ## 本地运行 ### 选项 A:Docker Compose(推荐) ``` docker compose up --build ``` - API:http://localhost:8001,交互式文档位于 http://localhost:8001/docs(从容器的内部端口 8000 映射而来——详见 `docker-compose.yml`) - Dashboard:http://localhost:3001 ### 选项 B:手动运行 ``` cd backend pip install -r requirements.txt # 启动你自己的 Postgres,然后: export DATABASE_URL=postgresql://sentinel:sentinel@localhost:5432/sentinelhub uvicorn app.main:app --reload ``` ## 使用样本数据测试接入 ``` curl -X POST http://localhost:8001/ingest/file \ -F "file=@docs/sample_auth.log" \ -F "source_hint=system" ``` 然后检查是否成功写入: ``` curl http://localhost:8001/logs/stats/summary curl "http://localhost:8001/logs/?event_type=auth_failure" ``` 样本日志包含一段模拟的暴力破解爆发记录(在约 20 秒内来自 `203.0.113.5` 的 10 次 SSH 登录失败,涉及 8 个不同的用户名)。 ## 测试检测(第 2 阶段) ``` # 1. 摄取示例日志(如果你还没有这样做) curl -X POST http://localhost:8001/ingest/file \ -F "file=@docs/sample_auth.log" \ -F "source_hint=system" # 2. 运行检测引擎 curl -X POST http://localhost:8001/detect/run # -> {"new_alerts": 1} # 3. 查看触发了什么 curl "http://localhost:8001/alerts/?src_ip=203.0.113.5" ``` 因为样本爆发涉及 8 个不同的用户名(admin, root, test, oracle, postgres, ubuntu, pi, git),所以它被正确分类为 `credential_stuffing`(高严重性),而不是普通的 `brute_force_login`——狂扫大量账户与反复猜测单个账户的密码是两种不同的、更为自动化的模式。两者均映射到 MITRE **T1110**。 对相同数据重新运行 `POST /detect/run` 会返回 `{"new_alerts": 0}`——每个 `LogEvent` 在被扫描一次后都会被标记为 `processed_for_detection`,因此不会产生重复告警。 ### 运行自动化测试 ``` docker compose exec backend pytest -v ``` `backend/app/tests/test_detection.py` 会通过真实的 API 接入样本日志,运行检测,并断言 `203.0.113.5` 的 `T1110` 告警已创建——并且第二次运行不会产生重复。 ### Schema 说明 第 2 阶段向 `LogEvent` 添加了 `processed_for_detection` 列。由于该项目目前还没有 Alembic 迁移(这是一个已知的“下一步计划”——见下文),如果你正在从第 1 阶段升级 Postgres volume,你需要么删除受影响的表(如果它们是空表/测试数据则没问题),要么运行: ``` ALTER TABLE log_events ADD COLUMN processed_for_detection BOOLEAN NOT NULL DEFAULT false; ``` ## 项目状态 - [x] 第 1 阶段:接入管道 + 规范化的日志存储 - [x] 第 2 阶段:检测引擎 + MITRE ATT&CK 映射 - [x] 第 3 阶段:威胁情报丰富化 - [x] 第 4 阶段:Dashboard - [ ] 第 5 阶段:蜜罐集成——已跳过(可选延伸目标) - [x] 第 6 阶段:CI/CD + 部署指南 + 生产规范 有关部署到 Render 的信息,请参阅 **[DEPLOYMENT.md](DEPLOYMENT.md)**。
标签:PostgreSQL, React, Syscalls, 威胁情报, 安全告警, 安全运营, 开发者工具, 扫描框架, 测试用例, 请求拦截, 逆向工具