pavel-kalmykov/phishing-radar
GitHub: pavel-kalmykov/phishing-radar
基于证书透明度日志的实时钓鱼基础设施检测系统,通过模糊字符串匹配识别仿冒域名并与多源威胁情报交叉关联。
Stars: 0 | Forks: 0
# 钓鱼雷达
基于证书透明度日志的实时钓鱼基础设施检测。在证书颁发时标记域名冒充行为,并将检测结果与活跃的恶意软件情报(CISA KEV、abuse.ch、Spamhaus、MITRE ATT&CK)进行交叉比对。
[](LICENSE)
[](https://www.python.org/downloads/)
[](#archive-mode)
**数据采集窗口:** 2026-04-23 至 2026-05-05。该项目作为实时云部署运行了 12 天,现在作为零依赖的冻结归档保存。该仪表板完全可探索,无需 API 密钥、Docker 或云账号。
## 快速开始
```
git clone https://github.com/pavel-kalmykov/phishing-radar.git
cd phishing-radar
uv sync
ARCHIVE_MODE=1 streamlit run dashboard/app.py
```
在 `http://localhost:8501` 打开。所有六个标签页均可正常使用:概览、实时钓鱼流、威胁态势、地图、健康状况、技术栈。归档横幅表明数据已冻结;日期选择器已锁定至采集范围。
## 为什么会有这个项目
每个钓鱼网站都需要 TLS 证书。浏览器会将非 HTTPS 网站标记为不安全,因此攻击者会从 Let's Encrypt 和其他公共 CA 为仿冒域名申请证书。这些证书在颁发后的几秒钟内就会出现在证书透明度日志中。
如果你持续关注这个数据流,就能在第一封钓鱼邮件发送之前,在诈骗基础设施搭建过程中发现它们。Phishing Radar 持续监控该数据流,并回答两个问题:
1. 目前有哪些品牌正在被仿冒?
2. 在这些可疑证书中,哪些托管在已知具有敌意的设施上(活跃的僵尸网络 C2、被劫持的 IP 空间、存在被利用的 CVE 的供应商)?
## 仪表板
六个标签页,全部从 97 MB DuckDB 快照中预聚合的 dbt marts 读取数据:
| 标签页 | 显示内容 |
|---|---|
| **概览** | 最常被仿冒的品牌、按恶意软件家族分类的活跃 C2(悬停查看上下文)、检测量趋势 |
| **实时钓鱼流** | 每小时标记的证书数量、主要颁发 CA、带有相似度评分的最新 50 项检测 |
| **威胁态势** | CISA KEV 每月新增、Spamhaus DROP/EDROP 明细、按勒索软件比例排名的 KEV 供应商、按国家/地区分类的 C2 |
| **地图** | 散点地理图,每个托管 C2 基础设施的国家/地区对应一个标记,按活跃数量调整大小,带有恶意软件家族提示框 |
| **健康状况** | 端到端管道丢失监控(WebSocket 到检测器跃点)、心跳延迟、每个 worker 的吞吐量 |
| **技术栈** | 流式管道、批量摄取和数据源的架构参考面板 |
## 架构(原云部署)
```
flowchart LR
subgraph src[Public sources]
CT[Certificate Transparency logs]
KEV[CISA KEV]
FEO[abuse.ch Feodo Tracker]
SPAM[Spamhaus DROP/EDROP]
MITRE[MITRE ATT&CK]
MM[MaxMind GeoLite2]
end
subgraph fly[Fly.io apps]
CS[certstream-server-go]
PROD[Python producer]
DET[PyFlink detector]
SINK[Kafka to MotherDuck sink]
KES[Kestra orchestrator]
end
subgraph cloud[Managed services]
RP[(Redpanda Cloud)]
MD[(MotherDuck)]
ST[Streamlit Cloud]
end
CT --> CS -->|WebSocket| PROD -->|certstream_events| RP
RP --> DET -->|suspicious_certs| RP --> SINK --> MD
KEV --> KES
FEO --> KES
SPAM --> KES
MITRE --> KES
MM --> KES
KES -->|dlt + dbt| MD
MD --> ST
```
该管道通过具有 1 分钟滚动窗口的 PyFlink 检测器每秒处理约 200 个证书,应用 Damerau-Levenshtein 和 Jaro-Winkler 相似度算法,针对配置的品牌列表捕获域名仿冒和同形字攻击。检测结果通过具有幂等保证的 Kafka sink 落地到 MotherDuck,然后由 18 个 dbt marts 对数据进行预聚合以供仪表板使用。
## 归档模式
云部署于 2026-05-05 结束,当时托管服务(Redpanda Cloud、MotherDuck)已到期。该归档在此代码仓库中保存了每个仪表板 mart 和 134,000 条最新检测结果,全部包含在一个 97 MB 的 DuckDB 文件中。设置 `ARCHIVE_MODE=1`,仪表板将直接读取该文件,实现零外部依赖。
## 技术栈
| 层级 | 工具 | 备注 |
|---|---|---|
| 流代理 | Redpanda (Kafka API) | 采集期间使用云服务;完整回放需通过 Docker 使用本地服务 |
| 流处理 | PyFlink DataStream | 1 分钟滚动窗口,域名仿冒 + 同形字检测 |
| 批量摄取 | dlt | CISA KEV、Feodo、ThreatFox、Spamhaus、MITRE、MaxMind |
| 编排 | Kestra | 计划批处理流 |
| 数据仓库 | DuckDB | 实时运行期间为 17 GB;97 MB 归档快照 |
| 数据转换 | dbt (dbt-duckdb) | 18 个预聚合 marts |
| 仪表板 | Streamlit | 归档模式($0)或本地运行 |
## 数据源
| 来源 | 类型 | 更新频率 |
|---|---|---|
| 证书透明度日志(通过 certstream-server-go) | WebSocket | ~200 证书/秒 |
| CISA KEV 目录 | JSON | 每天 |
| abuse.ch Feodo Tracker | JSON | 每分钟 |
| abuse.ch ThreatFox | JSON | 每分钟 |
| Spamhaus DROP / EDROP | TXT | 每天 |
| MITRE ATT&CK (Enterprise) | STIX 2 JSON | 每月 |
| MaxMind GeoLite2 | CSV | 每周 |
## 完全本地运行(带实时管道)
如果你想使用实时 CertStream 订阅源运行完整管道,你需要 Docker、Python 3.11+、`uv` 和 `just`:
```
cp .env.example .env # no cloud tokens needed
just setup # Python deps
just up-local # docker-compose: Redpanda + certstream + Kestra
export DATABASE_URL=data/local.duckdb
just producer & # CertStream to local Redpanda
just detect & # PyFlink detector (needs JDK 17)
just sink & # Kafka to local DuckDB
just monitor & # Observability
just batch # one-shot batch ingestion
just dbt-run-local # dbt transforms
just dashboard # Streamlit at localhost:8501
```
完整设置将写入 `data/local.duckdb`(预计在数天内会增长到数十 GB)。归档快照是在 12 天的采集窗口之后从同一管道中提取的。
## 仓库布局
```
.
├── batch/ # dlt pipelines (one module per source)
├── dashboard/ # Streamlit app
├── data/ # archive.duckdb (97 MB, committed)
├── dbt/ # dbt project (models, tests, macros)
├── deploy/ # fly.toml per Fly app (historical)
├── kestra/flows/ # Kestra flow definitions (YAML)
├── streaming/
│ ├── producer/ # CertStream to Kafka
│ ├── flink/ # PyFlink detection job
│ ├── sink/ # Kafka to DuckDB with idempotency
│ └── observability/ # Pipeline health monitor
├── tests/ # pytest suite
├── Dockerfile # single image for all Python services
├── docker-compose.yml # Redpanda + certstream + Kestra
├── justfile # cross-OS task runner
├── pyproject.toml
└── README.md
```
## 测试与质量
- **pytest**:26 个断言,涵盖域名仿冒检测器和每个批处理摄取解析器(重试/退避、模拟 HTTP 响应)。
- **dbt**:22 个 schema 测试 + 4 个单一测试(IP 格式健全性、管道健康不变量、CVE 日期健全性、基础模型非空)。
- **ruff**:在 CI 中进行 linting。
- **检测器设计**:`docs/detection_alternatives.md` 记录了从 Levenshtein 到 Damerau-Levenshtein + Jaro-Winkler 的迁移,以及为何放弃 MinHash。
- **内存分析**:`docs/memory_profile.md` 记录了每个服务的 RSS 峰值和规格调整决策。
## 已知局限性
这些是有意做出的权衡:
- **至少一次,而非精确一次。** sink 在 DuckDB 刷新后提交 Kafka 偏移量。如果在刷新和提交之间被终止,下一次运行将进行重放,并在 mart 层进行去重。这适用于分析场景;但不适合用于计费。
- **检测延迟下限。** 1 分钟的滚动窗口保持状态有界。证书在颁发后 60-120 秒出现在仪表板中。这是近实时,而非亚秒级。
- **CT 数据流空白。** 如果生产者与 WebSocket 断开连接,空白期间的事件不会被重放。存在重连逻辑;但没有重放机制。
- **单实例服务。** 每个 Fly app 运行一台机器。没有 HA(高可用性),没有领导者选举。恢复依赖于 Fly 的重启策略。
- **品牌白名单范围。** 检测器仅针对配置的品牌(`STREAMING_BRAND_LIST_PATH`)标记冒充行为。根据设计,列表之外的任何内容都是不可见的。
- **GeoLite2 准确性。** 免费层级,非商业级别。某些 IP 只能解析到国家级别。地图会对并置的标记进行抖动处理,以真实反映分辨率情况。
## 许可证
MIT。
标签:CISA KEV, Cloudflare, CT logs, dbt, DE Zoomcamp 2026, DuckDB, HTTPS证书, Kubernetes, MITRE ATT&CK, Python, Streamlit, TLS证书, 品牌保护, 域名仿冒, 威胁情报, 开发者工具, 开源, 恶意软件情报, 数据工程, 无后门, 期末项目, 网络安全, 访问控制, 证书透明度日志, 请求拦截, 逆向工具, 钓鱼检测, 隐私保护