P1rate5ec/threat-tea

GitHub: P1rate5ec/threat-tea

一款将 AbuseIPDB、AlienVault OTX 和 VirusTotal 三大威胁情报源的 IP 信誉数据聚合为统一判定结果的防御性工具。

Stars: 0 | Forks: 0

# 🍵 Threat 茶 ### 将三个嘈杂的威胁情报源泡入一杯平静的茶中。 ![python](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white) ![license](https://img.shields.io/badge/license-MIT-blueviolet) ![tests](https://img.shields.io/badge/tests-24%20passing-brightgreen) ![interface](https://img.shields.io/badge/interface-CLI%20%2B%20Web-22c55e) ![metrics](https://img.shields.io/badge/metrics-Prometheus-E6522C) ![transmits](https://img.shields.io/badge/transmits-nothing%20by%20default-success) *三个源,三种判定,三个不同的答案。现在该怎么办?*
`threat-tea` 接收一个 IP 地址,以近似并行的方式向三个信誉提供商查询, 将答案浓缩为一个判定结果 + 分数,并对结果进行缓存,因此您永远无需为同一次查询付费两次。它提供了 Rich 终端 UI、Flask 仪表板、JSON API 以及用于 Grafana 的 Prometheus 指标。 它是一个**防御性**工具:它只*读取*有关您提供的指标的公共信誉数据。它从不扫描、攻击或触碰目标主机。 ## 1. 它的功能及存在原因 威胁情报提供商用三种不同的方式回答同一个问题 —— *“这个 IP 是否恶意?”*: | 提供商 | 提供的信号 | threat-tea 如何评分 | | --- | --- | --- | | **AbuseIPDB** | 滥信置信度 % + 报告计数 | 直接使用置信度分数 (0–100) | | **AlienVault OTX** | 引用该 IP 的 pulses 数量 | `min(100, pulses × 20)` | | **VirusTotal** | 最近分析中的恶意/可疑计数 | `min(100, malicious×15 + suspicious×5)` | 为警报进行情报扩充的分析人员不应该被迫打开三个浏览器标签页、学习三种 JSON 结构,并肉眼评估三种评分标准。threat-tea 将这一切标准化为一个 `Finding`: ``` indicator · type · max_score (0–100) · verdict · [per-source rows with raw evidence] ``` **核心的 `max_score` 是任何单一来源给出的最严厉评价**(分析人员需要最响亮的警报),但每个来源行的原始内容都被原样保留 —— 包括原始的提供商 JSON —— 因此您随时可以审计*原因*。UI 还会显示**相互印证**(`hits` = 有多少来源独立标记了它),这区分了“一个神经质的源”和“所有人的共识”。 **判定阈值**(稳定的 —— 有一个测试固定了这些值): | 分数 | 判定 | 颜色 | | --- | --- | --- | | `≥ 75` | `high` | 红色 | | `40–74` | `medium` | 黄色 | | `1–39` | `low` | 青色 | | `0` | `informational` | 绿色 (干净) | ## 2. 工作原理(数据流) ``` check-ip 45.83.64.1 │ ▼ ┌─────────────────────────┐ validate.parse_ip() │ 1. VALIDATE + NORMALIZE │ • must be a real IP (ipaddress) → blocks URL injection │ │ • must be public (is_global) → won't leak internal hosts └─────────────────────────┘ • canonicalized (dedupe key) │ ▼ ┌─────────────────────────┐ aggregate.aggregate_ip() │ 2. FAN OUT TO SOURCES │ AbuseIPDB / OTX / VirusTotal │ │ • unconfigured key → "skipped", not fatal │ │ • one source erroring → recorded, others continue └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ Finding(indicator, max_score, verdict, sources…) │ 3. NORMALIZE → FINDING │ max_score = worst source; hits = # that flagged it └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ store.save_finding() (SQLite, upsert by indicator) │ 4. CACHE │ findings(indicator PK, type, max_score, verdict, └─────────────────────────┘ sources_json, observed_at) │ ▼ ┌─────────────────────────┐ Rich panel/table (human) · pure JSON (--json) · │ 5. RENDER / SERVE │ Flask dashboard (/) · JSON API · /metrics (Grafana) └─────────────────────────┘ ``` 网络扇出**对失败采取宽容策略**:缺失的 API key 或提供商服务中断会变成一行带有简短原因的“已跳过”记录,而绝不会导致程序崩溃。在完全*没有*配置 key 的情况下,`check-ip` 会执行零网络 I/O 并返回一个 `informational` 发现 —— 这正是整个测试套件能够离线运行的原因。 ## 3. CLI 用法 全局标志(位于子命令之前): | 标志 | 效果 | | --- | --- | | `--db PATH` | SQLite 缓存位置(环境变量 `THREAT_TEA_DB`,默认为 `threat_tea.sqlite3`) | | `--plain` / `--no-color` | 禁用颜色/装饰(同时也遵循 `NO_COLOR` 环境变量) | | `--version` | 打印版本号 | 到处应用的输出规则: - `--json` → **向 stdout 输出纯 JSON**,始终如此,没有任何装饰。 - 管道 / `--plain` / `NO_COLOR` / 非 TTY → 纯净的纯文本(与旧脚本已经在解析的行相同)。 - 交互式终端 → Rich 横幅、面板、表格和加载动画。 ### `check-ip` — 查询单个 IP ``` threat-tea check-ip 45.83.64.1 --yes threat-tea check-ip 8.8.8.8 --yes --json # machine-readable threat-tea check-ip 10.0.0.5 --yes --allow-private # opt in to private ranges ``` | 标志 | 含义 | | --- | --- | | `-y, --yes` | 确认您已获得授权查询这些指标(或设置 `THREAT_TEA_ASSUME_YES=1`) | | `--allow-private` | 允许私有/保留/回环 IP(默认拦截) | | `--json` | 以纯 JSON 格式输出发现结果 | 示例交互式输出: ``` ╭─ 🍵 threat-tea ─────────────────────────────╮ │ steep three noisy feeds into one calm cup │ │ authorized threat-intel lookups only │ ╰─────────────────────────────────────────────╯ ╭─ finding ───────────────────────────────────────────────────────╮ │ │ │ 45.83.64.1 high (92) 2 source(s) flagged it │ │ │ │ source score summary │ │ ─────────────────────────────────────────────────────────── │ │ abuseipdb 92 Abuse confidence 92; reports 431 │ │ otx 60 OTX pulse references 3 │ │ virustotal 0 VT malicious=0, suspicious=0 │ │ │ ╰──────────────────────────────────────────────────────────────────╯ ``` 纯文本/管道输出保持原有的单行格式: ``` 45.83.64.1 high score=92 ``` ### `collect` — 批量处理包含 IP 的文件 ``` threat-tea collect --input iocs.txt --yes threat-tea collect --input iocs.txt --yes --delay 1.5 # throttle for rate limits threat-tea collect --input iocs.txt --yes --json > out.json ``` 空行和 `#` 注释会被忽略,重复项会被去重(按首次出现的顺序),无效或私有的行会被跳过并在 stderr 中报告 —— 运行会继续执行。文件有大小上限(5 MB / 10 万行),因此失控的文件不会耗尽内存。 | 标志 | 含义 | | --- | --- | | `--input PATH` | 以换行符分隔的 IP 列表(必填) | | `--delay SECONDS` | 两次查询之间的暂停时间,以遵守提供商的速率限制(默认为 0) | | `-y, --yes` / `--allow-private` / `--json` | 同上 | ### `findings` — 显示缓存内容 ``` threat-tea findings # table in a terminal, JSON when piped threat-tea findings --verdict high # filter threat-tea findings --limit 20 threat-tea findings --json | jq '.[].indicator' ``` `findings` 在**非交互式终端下始终输出 JSON**,因此 `threat-tea findings > report.json` 依然能像以前一样正常工作。在真正的终端中,您会看到一个排序后的表格(最严重的判定排在最前),包含分数、印证命中数、来源计数和新鲜度。 ### `serve` — 仪表板、API、指标 ``` threat-tea serve # binds 127.0.0.1:5064 by default threat-tea serve --host 127.0.0.1 --port 8080 ``` | 路由 | 用途 | | --- | --- | | `GET /` | HTML 仪表板 | | `GET /api/findings` | 以 JSON 格式输出缓存的发现结果 | | `GET /metrics` | 供 Prometheus 使用的 `threat_tea_risk_score`, `threat_tea_indicators_total` | 每个响应都带有强化安全性的标头(`X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`,严格的 `Content-Security-Policy`,`Referrer-Policy`)。 ## 4. 安全与授权说明 这是一个防御性的只读工具,但它仍然会将您提供的每个指标发送给第三方。threat-tea 将这一点明确化: - **授权关卡。** 网络命令(`check-ip`, `collect`)在您确认授权前拒绝运行 —— 请传入 `--yes`,设置 `THREAT_TEA_ASSUME_YES=1`,或在交互式终端中回答提示。在未确认授权的情况下通过管道输入,它会拒绝执行(退出码 `2`),而不是默默地将某人的 IP 信息发送出去。 - **无内部拓扑泄露。** 私有/保留/回环地址**默认被拦截** —— 提供商没有关于它们的数据,提交它们可能会泄露您的内部结构。请在明确知晓后果的情况下使用 `--allow-private` 覆盖此设置。 - **防注入。** 每个指标在被拼接到提供商 URL 之前,都会使用标准库 `ipaddress` 模块进行解析,因此 `1.2.3.4/../../x` 绝不会离开进程。SQL 全程使用绑定参数。 - **输出中无机密。** API key 存在于请求*头*中,绝不出现在 URL 或日志中;源错误信息被截断为一行短文本。 - **安全的 `serve` 默认设置。** 绑定到 `127.0.0.1`;在任何非回环绑定时发出警告;并且**拒绝在非回环绑定时使用 `--debug`**,因为 Werkzeug 的交互式调试器是一个远程代码执行攻击面。 - **有界的输入。** `collect` 文件有大小和行数上限。 请仅查询您被授权调查的指标。 ## 5. 安装、运行与测试 ### 安装 ``` cd threat-tea python -m venv .venv && source .venv/bin/activate # optional pip install -r requirements.txt cp .env.example .env # then add whatever keys you have ``` 配置您拥有的任何 key(任意子集均可;缺失的将被跳过): ``` ABUSEIPDB_API_KEY=... OTX_API_KEY=... VIRUSTOTAL_API_KEY=... ``` ### 不安装直接运行(通过 PYTHONPATH) ``` PYTHONPATH=src python -m threat_tea.cli check-ip 8.8.8.8 --yes PYTHONPATH=src python -m threat_tea.cli findings PYTHONPATH=src python -m threat_tea.cli serve ``` ### 测试 快速、离线、无网络且无休眠: ``` PYTHONPATH=src python -m pytest -q ``` ### Grafana 技术栈(可选) ``` docker compose up --build ``` Prometheus 抓取 `/metrics`;Grafana 配置地址为 `http://127.0.0.1:3000` (`admin` / `threat-tea`)。 ## 前置条件 Python 3.11+,以及 `flask`、`requests`、`prometheus-client` 和 `rich` (均包含在 `requirements.txt` 中)。Docker 仅用于 Grafana 技术栈。 ## 参考资料 - [AbuseIPDB API v2](https://docs.abuseipdb.com/) - [AlienVault OTX DirectConnect API](https://otx.alienvault.com/api) - [VirusTotal API v3](https://docs.virustotal.com/reference/overview) · [IP 报告端点](https://docs.virustotal.com/reference/ip-info) ## 🏷️ 为什么叫 "Threat Tea"? 泡上这些情报源,倒出一杯茶。AbuseIPDB、AlienVault OTX 和 VirusTotal 很少能完全达成共识,而且无论您碰巧先查询哪一个,都不应该由它来决定您的判定结果。所有三个来源的相互印证胜过盲目相信任何单一来源 —— 因此,输出不仅告诉您一个 IP 看起来*有多糟糕*,还告诉您**有多少独立的来源实际支持这一点**。 ## 🔬 本工具的构建方式 **目的。** 一个让人心平气和的 IP 信誉聚合器:给它一个指标,它就会将 AbuseIPDB、OTX 和 VirusTotal 泡成一个带有颜色编码的判定结果,包含相互印证和原始证据 —— 默认安全,并为脚本提供纯 JSON 输出。 **工作原理。** 每个 IP 都经过验证和规范化处理,然后向每个已配置的源进行查询(key 保留在请求头中)。结果缓存在 SQLite 中,作为携带最高分、判定结果以及有多少来源独立标记了该 IP 的 **hits**(命中)计数的 findings。`collect` 批量处理一个包含指标的文件;`findings` 对存储进行过滤和渲染。 **出色的 CLI。** `check-ip` 发现面板带有判定标签、印证行和每个来源的分数/汇总表;排序后的 `findings` 表格(最严重的排在最前)带有分数/命中数/来源计数/新鲜度;`collect` 进度条和摘要面板;一致的严重性递进(绿色干净 → 青色低语 → 黄色关注 → 红色立即行动)。 **关键改进。** *功能性:* 严格的 IP 验证,端到端支持 IPv6(正确的 OTX IPv4/IPv6 端点,对压缩格式与展开格式进行去重);相互印证的 `hits` 信号;`collect` 进行去重,跳过并报告无效/私有的行同时继续运行,限制文件大小(5 MB / 10 万行),并支持 `--delay`;参数化的 SQL 过滤器。*安全性:* 出站流量的授权关卡(`--yes` / `THREAT_TEA_ASSUME_YES=1` / 交互式模式;未确认授权的管道输入将被拒绝,退出码 2);默认拦截私有/保留/回环 IP(使用 `--allow-private` 覆盖),这样您就不会将内部拓扑泄露给第三方;在进入提供商 URL 之前,使用标准库 `ipaddress` 解析每个指标;API key 绝不出现在 URL 或日志中,错误摘要修剪为 160 个字符。 **示例。** ``` PYTHONPATH=src python -m threat_tea.cli check-ip 45.83.64.1 --yes ``` ## ⚖️ 授权使用与安全宪章 **这些是防御性工具,适用于您拥有或获得明确授权评估的系统、文件、网络和人员。** 在运行任何内容之前,请阅读以下声明: - **授权不是可选的。** 钓鱼模拟、网络扫描、IP 信誉查询和 Web 应用探测都会触及他人的系统或数据。请先获得书面授权。一些工具*拒绝采取行动*,直到您声明已获得授权(`--yes`、`--authorized-training`、`--i-have-authorization`、`--i-am-authorized` 等)。 - **默认安全。** 每个 Web UI 都绑定到 `127.0.0.1`(回环地址)。出站流量、实时发送和主动扫描都受显式标志控制 —— 演练、被动模式或拒绝并警告始终是默认行为。 - **杜绝意外的危险操作。** Flask 的 `--debug`(Werkzeug 交互式调试器在任何回溯时都是远程执行漏洞)会受到强烈警告,并在脱离回环地址时被彻底拒绝。不受信任的输入有大小限制、经过验证并被渲染为无害内容,因此恶意的文件或日志行不会导致崩溃 —— 或接管 —— 您的终端。 - **输出中无机密。** API key 保留在请求头中,密码来自环境变量,没有任何敏感信息被记录或打印。 这些不是攻击性工具。它们不包含任何漏洞利用、凭证收集器或 payload。如果某个工具*可能*被滥用,我们在构建时就使其能够从结构上抵御这种滥用。 ## 🧪 开发 ``` python -m venv .venv && source .venv/bin/activate pip install -e . pytest -q # 24 tests, no network, no sleeps threat-tea --help ``` ## 📄 许可证 基于 **MIT License** 发布。参见 [LICENSE](LICENSE)。
防御性工具。没有漏洞利用,没有 payload,没有凭证收集器。
标签:Flask, PB级数据处理, Python, 威胁情报, 安全运维, 开发者工具, 无后门, 自定义请求头, 逆向工具