jtshor14899/threat-dash
GitHub: jtshor14899/threat-dash
一款面向家庭实验室的开源威胁情报仪表板,将入站流量、出站归属、威胁情报与终端安全整合在单一可视化界面中。
Stars: 0 | Forks: 0
# threat-dash
[](./LICENSE)
[](./Dockerfile)
[](./Dockerfile)
[](./Dockerfile)
[](https://github.com/jtshor14899/threat-dash/issues)
[](https://github.com/jtshor14899/threat-dash/stargazers)
(Run scripts/seed-demo-data.py to populate a copy with realistic synthetic data — see SCREENSHOTS.md.)
## 目录
- [功能简介](#what-it-does)
- [截图展示](#screenshots)
- [同类对比](#how-it-compares)
- [快速开始](#quick-start)
- [拦截后端](#block-backends)
- [终端节点可见性 (Wazuh)](#endpoint-visibility-wazuh)
- [部署模式](#deployment-patterns)
- [架构](#architecture)
- [配置说明](#configuration)
- [API 提供商 — 免费与收费](#api-providers--whats-free-whats-not)
- [REST + SSE 接口](#rest--sse-endpoints)
- [性能表现](#performance)
- [安全性](#security)
- [路线图](#roadmap)
- [贡献指南](#contributing)
- [许可证](#license)
## 功能简介
Threat-dash 监控四个方面,并将它们整合到一个实时视图中:
1. **入站流量** — 访问您 Cloudflare zone 的请求。每一个 WAF 事件,每一次
被拦截 / 验证 / 允许的请求,每一次 Cloudflare Access 登录
尝试,经过 GeoIP 丰富处理后,通过动态弧线投影到 3D 地球仪上,
指向您的 homelab。
2. **出站流量** — 您的容器正在向外请求的内容。sidecar 从
每个容器的 netns 读取 `/proc/net/tcp`,进行去重,并将
目标地址输入到同一个地图中(颜色不同,方向不同)。
3. **威胁情报** — 每个出站目的地都会自动与
GreyNoise、Censys、Shodan 以及(按需)VirusTotal 进行比对丰富。🛰 情报页面
展示完整的主机配置文件:开放服务、软件栈、TLS 证书、
SSH banner、WHOIS、DNS、CVE、威胁评分汇总。
4. **终端节点** — 来自 **Wazuh** SIEM/XDR 管理器的 agent 清单、漏洞发现和 FIM 事件。
基于严重程度分类的单个 agent CVE 钻取分析;整个集群的状态 KPI。参见
[docs/WAZUH.md](docs/WAZUH.md)。
您还将获得:
- 在 Cloudflare 边缘 *或* **pfSense** 防火墙上**点击拦截**
(基于别名,无需为每个 IP 单独创建规则 — 参见 [docs/PFSENSE.md](docs/PFSENSE.md))。
- **区域攻击面** — 选择一个区域(`country:US state:CA`,
`country:DE`,`asn:13335`,任何可用于 Shodan 过滤的参数)并查看有多少
主机暴露了 SSH / RDP / SMB / Redis / Mongo / Kibana / Docker API /
Modbus / MQTT / Elasticsearch / VNC 等。点击任意行即可深入查看
分面细分 — 主要组织、ASN、产品、版本、操作系统、
城市、CVE — 所有这些都在 Shodan 的 **免费 `oss` 层级**上。
- **按容器划分的流量归属** — 哪个容器在何时、通过哪个
端口与哪个 IP 进行了通信。
- **抽屉式导航** — 页眉下方的水平标签栏;点击
标签会在右侧弹出一个滑出式抽屉,显示该部分的内容。
地球仪在主视图中始终保持全屏显示,直到您需要查看详细信息。
- **浅色和深色主题**,**可调整大小的抽屉**,**键盘快捷键**
(`1`-`6` 切换标签,`T` 切换主题,`R` 刷新,`Esc` 关闭抽屉,`F` 实时流)。
- **仅使用 stdlib 的 Python 服务器** — `http.server` + `sqlite3` + `urllib` +
`maxminddb` + `cryptography`。没有 Flask,没有 SQLAlchemy,没有 Celery。
- **原生 JS 前端** — 使用 globe.gl + three.js 实现 3D 视图。客户端总计约 150 KB。
无构建步骤,无 node_modules。
## 截图展示
以下所有截图均来自通过 `scripts/seed-demo-data.py` 填充演示数据的副本 —
无需真实的 Cloudflare / Censys / GreyNoise / Shodan / VT 凭据即可
复现它们。截图获取方法请参见 [SCREENSHOTS.md](docs/SCREENSHOTS.md)。
Overview — animated globe + top-attacker country list, opened in the right-side drawer
|
Traffic — per-container outbound destinations, ranked
|
Blocks — Cloudflare and pfSense rules in one list, backend-badged
|
Endpoints — Wazuh agent fleet, status KPIs, CVE drilldown NEW
|
Outbound Intel — GreyNoise / Censys / Shodan / VT enrichment
|
Settings — every credential & toggle (Cloudflare, Shodan, Censys, GreyNoise, pfSense, Wazuh) editable at runtime, no restart. Env vars win and are marked locked.
|
## 同类对比
| 工具 | 功能 | threat-dash 的增值之处 |
| --- | --- | --- |
| [CrowdSec](https://crowdsec.net/) | 基于行为的 IPS,社区订阅源 | 3D 地球仪 + 出站可见性 + 在 CF 边缘点击拦截,替代 iptables |
| Cloudflare dashboard | 数据本身 | 单一面板涵盖入站 + 出站 + 情报,带有实时流和按容器划分的流量归属 |
| [Shodan](https://shodan.io/) | 互联网规模的扫描数据 | 我们*消费* Shodan;我们并不取代它。结合您自己的出站列表,提供基于目的地的情报 |
| [WatchYourLAN](https://github.com/aceberg/WatchYourLAN) | LAN 设备发现 | 范围不同 — WYL 是 L2 清单,threat-dash 是 L7 / 外部 |
| [Grafana + Cloudflare Loki](https://grafana.com/) | DIY 仪表板 | Threat-dash 就是仪表板本身。无需编写 PromQL/LogQL |
## 快速开始
```
# 1. clone
git clone https://github.com/jtshor14899/threat-dash.git
cd threat-dash
# 2. fill in API tokens (Cloudflare required for inbound data;
# Censys / GreyNoise / VT / Shodan optional but make the Intel page sing)
cp .env.example .env
$EDITOR .env
# 3. fetch the free GeoIP databases (~50 MB total, monthly refresh)
./scripts/setup-geoip.sh
# 4. up
docker compose up -d --build
# 5. (optional) seed with realistic synthetic data so the UI is interesting
# before any real Cloudflare events trickle in:
docker compose exec threat-dash python /scripts/seed-demo-data.py
```
仪表板现在位于 `http://127.0.0.1:5959/`。**不要将 5959
公开暴露** — 请使用以下部署模式之一作为前端。
## 拦截后端
| 后端 | 规则所在位置 | 模式 | 设置 |
| ------------- | ------------------------ | ---------------------------------- | ----- |
| **Cloudflare**| Zone IP Access Rules | 拦截、验证(3 种方式)、允许| 默认 — 使用您现有的 `CF_DASH_TOKEN`。 |
| **pfSense** | 您 pfSense 上的主机别名| 拦截、允许 | [docs/PFSENSE.md](docs/PFSENSE.md) — 需要安装 `pfSense-pkg-RESTAPI` 软件包。 |
各个后端相互独立 — 您可以运行其中一个,或另一个,或者同时连接
两者。拦截标签页的下拉菜单允许您为每个规则进行选择。
## 终端节点可见性
Threat-dash 接入 **Wazuh** SIEM/XDR 管理器,在专用的 **终端节点**
标签页中展示 agent 清单、漏洞发现和文件完整性事件。严格只读 — 拦截决策仍然通过 Cloudflare 或
pfSense 执行;Wazuh 仅用于提供可见性,而非执行。
| 后端 | 展示内容 | 您将获得什么 | 设置 |
| -------- | --------------- | ------------------------------------------------------------ | ----- |
| **Wazuh**| Manager REST API| agent 清单、状态 KPI、按 agent 划分的 CVE 钻取分析、FIM | [docs/WAZUH.md](docs/WAZUH.md) — 适用于任何 Wazuh 4.x 管理器(单节点 `wazuh-docker` 是最快捷的途径)。 |
内置的内存模拟器意味着您无需搭建
真实的 Wazuh 即可试用终端节点标签页:`docker compose -f docker-compose.yml -f
docker-compose.mock.yml up -d`。
## 部署模式
为 homelab 爱好者实际运行的架构量身定制的方案。选择一个;
所有方案均位于 [`examples/`](./examples) 目录下。
| 模式 | 适用场景 | TLS | 身份验证 | 是否公开? |
| --- | --- | --- | --- | --- |
| **[仅限局域网](./examples/lan-only-no-proxy/)** | 首次试用 / 受信任的 LAN+VPN | ❌ | 无 | 否 |
| **[Tailscale sidecar](./examples/tailscale-sidecar/)** | 您已经在使用 Tailscale | ✓ | tailnet ACLs | 否(通过 Funnel 则为是) |
| **[Traefik](./examples/traefik/)** | 已经在使用 Traefik(*arr/Jellyfin 架构) | ✓ Let's Encrypt | forward-auth | 可选 |
| **[Caddy](./examples/caddy/)** | 已经在使用 Caddy | ✓ Let's Encrypt | forward-auth | 可选 |
| **[Nginx Proxy Manager](./examples/nginx-proxy-manager/)** | 您喜欢 NPM 图形界面 | ✓ Let's Encrypt | NPM 访问列表 | 可选 |
| **[Cloudflare Tunnel](./examples/cloudflare-tunnel/)** | 无需端口转发的公开访问 | ✓ CF 边缘 | Cloudflare Access SSO | **是** ✓ |
| **[Authelia / Authentik](./examples/authelia-forward-auth/)** | 您运行自己的 SSO | 取决于代理 | TOTP/WebAuthn | 可选 |
**推荐大多数 homelab 使用**:`tailscale-sidecar`(最快捷)或
`cloudflare-tunnel + cloudflare-access`(最完善,对公开暴露安全)。
## 架构
```
┌──── Cloudflare edge ────┐ ┌──── Wazuh manager ────┐
│ GraphQL Analytics │ │ REST API :55000 │
│ Firewall events │ │ agents / vulns / FIM │
│ Access audit log │ │ JWT auth, cached │
└────────────┬────────────┘ └──────────┬─────────────┘
│ │
▼ 60s poll ▼ on-demand
┌──────────────────────────────────────┐ ┌──────────────────┐
│ collector.py (background thread) │ │ wazuh_client.py │
│ + outbound_collector.py (sidecar) │ │ (per-request) │
└────────────────────┬─────────────────┘ └────────┬─────────┘
▼ │
┌──────────────────────────────────────┐ │
│ GeoIP / ASN (DB-IP Lite mmdb, free) │ │
│ Auto-enrich (GreyNoise + Censys) │ ← 5/tick │
└────────────────────┬─────────────────┘ │
▼ │
┌─── SQLite (WAL, /data) ────┐ │
│ events, blocks, recon │ │
│ vt_cache, scans, settings │ │
└──────────────┬─────────────┘ │
▼ │
┌──────────────────────────────────────────────────┴─────┐
│ server.py — stdlib http.server │
│ REST + Server-Sent Events on :5959 │
└─────┬───────────────────────┬───────────────────────────┘
▼ ▼
┌────────────────────┐ ┌──────────────────────┐
│ Cloudflare API │ │ pfSense REST API v2 │
│ IP Access Rules │ │ host-alias mutate │
│ (per-IP rules) │ │ + apply │
└────────────────────┘ └──────────────────────┘
▲ ▲
│ click-to-block │
└───── from any IP row ─┘
your reverse proxy
▼
browser (globe.gl + drawer UI)
```
## 配置说明
配置 threat-dash 有两种方式 — 请选择适合您工作流程的一种:
1. **通过设置界面**(页眉中的 ⚙ 图标,或按 `,` 键)。在
仪表板中编辑 API token、homelab 品牌信息、自身流量检测和出站规则。
更改在下次 API 调用时生效 — 无需重启容器。
密钥在**传输过程中会被掩码处理**(只有最后 4 个字符会离开
服务器)。每个提供商的“测试”按钮会在数据源验证每个 token。
2. **通过 `.env`**(经典方式)。环境变量始终优先于界面设置的值 —
设置页面会将它们显示为“被环境变量锁定”。现有部署
不受影响。
完整列表请参见 [`.env.example`](./.env.example)。重点如下:
| 变量 | 是否必需? | 备注 |
| --- | --- | --- |
| `CF_DASH_TOKEN`, `CF_ZONE_ID`, `CF_ACCOUNT_ID` | 用于入站 | Cloudflare API。作用域记录在 `.env.example` 中。 |
| `HOMELAB_LAT`, `HOMELAB_LON`, `HOMELAB_LABEL` | 推荐 | 地球仪上的图钉位置 + 页眉中的品牌文本 |
| `VT_API_KEY` | 可选 | VirusTotal v3 免费层(每天 500 次查询) |
| `SHODAN_API_KEY` | 可选 | 免费 `oss` 层 — 区域攻击面 + 分面钻取 |
| `CENSYS_TOKEN` | 可选 | Censys Platform PAT(按主机丰富数据,免费) |
| `CENSYS_API_ID` + `CENSYS_API_SECRET` | 可选 | Censys Search v2(每月 250 次查询,免费) |
| `GREYNOISE_API_KEY` | 可选 | 社区版无需 key 即可工作;认证可提升速率限制 |
| `SELF_EMAILS`, `SELF_IPS`, `SELF_ASN_PREFIXES` | 可选 | 隐藏您自己的流量 |
| `OUTBOUND_EXTRA_RANGES` | 可选 | 逗号分隔的 CIDR,将其视为内部网络 |
| `DEMO_MODE` | 可选 | `1` 禁用所有实时轮询 — 用于截屏 |
## API 提供商 — 免费与收费
| 提供商 | 免费 | 付费要求 |
| --- | --- | --- |
| **VirusTotal** | 每天 500 次 v3 查询 | 更高配额,深度搜索 |
| **Censys Platform** | 按主机丰富数据 (PAT) | 搜索、聚合 |
| **Censys Search v2** | 每月 250 次搜索查询 | 批量结果,更高配额 |
| **GreyNoise** | 社区分类(每天 50 次,无需 key) | RIOT 背景,深度搜索 |
| **Shodan** | `/host/count` + 分面(`oss` 计划) | `/host/
`, `/host/search` |
任何您没有提供 key 的功能都会在界面中隐藏,并带有
解释原因的提示。Threat-dash 始终会平滑降级 — 您甚至仅使用
Cloudflare + DB-IP 运行,依然能获得一个有用的仪表板。
## REST + SSE 接口
UI 是基于轻量级 REST API 构建的瘦客户端:
```
GET /api/stats?range=24h&self=hide&direction=in|out
GET /api/arcs?range=24h&limit=400
GET /api/events?range=24h&limit=200
GET /api/intel/outbound?range=24h&limit=250
GET /api/signins?range=24h
GET /api/containers?container=&range=24h
GET /api/blocks
POST /api/block {ip, mode?, reason?, expires_at?}
DEL /api/blocks/
PATCH /api/blocks/ {mode?, reason?, expires_at?}
GET /api/recon/status
GET /api/shodan/surface?base=
GET /api/shodan/drill?base=&category=
GET /api/shodan/host/
GET /api/censys/host/
GET /api/recon/search?q=&per_page=25
GET /api/greynoise/
GET /api/vt/{ip,domain,hash,url}/
POST /api/scan {ip, profile=common|extended, force?}
GET /stream Server-Sent Events
GET /healthz 200 ok (used by HEALTHCHECK)
```
这对于将 threat-dash 脚本化集成到更大的 SOAR 类工作流中非常有用 — 例如,通过 Slack 的斜杠命令
拦截一系列 IP。
## 性能表现
前端经过精心优化,以确保不会使您的浏览器卡顿:
- SSE 事件在每个 200 ms 的 rAF 周期中进行批量处理(不会针对每个事件重新渲染)。
- 无论数据流速度如何,地球仪的重绘频率都限制在约 3 fps。
- 当数据特征未改变时,`renderStats` 会短路跳出。
- 当 `document.hidden` 时,定期刷新频率会降至 2 分钟一次。
- 所有列表更新均使用 `DocumentFragment` + `replaceChildren`。
Python 服务器:
- 单进程,多线程 `HTTPServer`。每个 SSE 客户端都会获得一个有界的
`queue.Queue`,因此缓慢的消费者不会导致广播阻塞。
- 采用 SQLite WAL 模式,写操作使用单个 `threading.Lock`;读操作
非同步。
- 出站数据丰富处理的速率限制为每周期(每 60 秒)5 个 IP,因此
免费层级的 API 配额不会因突然出现的大量新
目的地而被耗尽。
在一台普通的 VM(2 vCPU / 2 GB)上,每天处理约 6 万个事件,RSS 占用约为 80 MB。
## 安全性
Threat-dash 是一款安全工具。它理应遵循高标准。
- **切勿在没有前置身份验证的情况下公开暴露 5959 端口。** 系统中没有
用户模型。任何获取了 URL 的人都可以在您的 Cloudflare 边缘拦截 IP。
- 以 **非 root** 用户(UID 1000)运行,采用多阶段构建镜像,丢弃了所有 Linux
权限,并设置了 `no-new-privileges:true`。
- 对 `/healthz` 执行 `HEALTHCHECK`,以便编排器在其卡死时能及时发现。
- 出站 TCP 扫描仪由 **操作员手动触发**,仅执行连接 + banner 抓取 — 没有
漏洞利用路径。请确认在您所在的司法管辖区内进行扫描是否合法。
- `.env` 已被 git-ignore;每季度轮换一次 Cloudflare token。
完整的威胁模型 + 加固检查清单位于
[`docs/SECURITY-HARDENING.md`](./docs/SECURITY-HARDENING.md)。
报告漏洞:[`SECURITY.md`](./SECURITY.md)。
## 路线图
- [ ] 为没有使用自己的代理作为前端的用户提供内置的 basic-auth / 代理标头认证
- [ ] 保存查询捆绑包(“每周区域攻击面差异比对”)
- [ ] 在达到威胁评分阈值时触发 ntfy / Slack / Discord webhook
- [ ] 将出站 CVE 与您镜像的 Trivy SBOM 扫描结果进行交叉比对
- [ ] 将镜像发布到 GHCR,实现拉取而非构建的部署
- [ ] 接入更多提供商:AbuseIPDB、AlienVault OTX、IPinfo Lite
如果您想支持某项功能或提出不同的建议,请提交一个 issue。
## 许可证
[MIT](./LICENSE)。运行时的 DB-IP Lite 数据库由
[db-ip.com](https://db-ip.com) 提供,基于 CC-BY 4.0 协议。
由 homelab 运维者为 homelab 运维者打造。如果它帮助您
免受僵尸网络的凭证撞库攻击,请[⭐ 给仓库点星][stars] —
这是我们仅有的营销预算。
标签:AppImage, Docker, PB级数据处理, Python, Web应用防火墙, 可视化仪表板, 威胁情报, 安全运维, 安全防御评估, 家庭实验室, 开发者工具, 数据可视化, 无后门, 请求拦截, 逆向工具