subfinder的crtsh数据源实现深度剖析:PostgreSQL直连+HTTP API双通道回退设计
【免费下载链接】subfinderFast passive subdomain enumeration tool.项目地址: https://gitcode.com/gh_mirrors/su/subfinder
subfinder是一款快速被动子域名枚举工具,它通过聚合各类在线被动数据源,无需发送任何探测流量即可挖掘出目标域名的有效子域名。本文将深入剖析其内置的crtsh数据源(基于证书透明度日志 crt.sh):为什么它要同时实现PostgreSQL 直连与HTTP API两条通道?回退逻辑又是如何保证结果稳定性的?
一、先认识 subfinder 的数据源体系
subfinder 采用高度模块化的架构:每个数据源都是一个独立的 Go 包,只要实现统一的Source接口(见 pkg/subscraping/types.go),就能被枚举引擎无缝接入。
一个数据源需要回答几个核心问题:
| 接口方法 | 作用 |
|---|---|
Run | 拉取该源的子域名结果 |
Name/IsDefault | 数据源名称,是否默认启用 |
HasRecursiveSupport | 是否支持递归查询子域名的子域名 |
KeyRequirement | 是否需要 API Key(无需/可选/必需) |
crtsh 数据源的完整实现位于 pkg/subscraping/sources/crtsh/crtsh.go,并被注册进全部 52 个数据源的清单中(pkg/passive/sources.go)。它的三个"自我声明"很关键:
- 默认启用(
IsDefault返回true),无需 API Key(NoKey) - 支持递归查询(
HasRecursiveSupport返回true),因此能配合-recursive参数对已有子域名继续挖 - 零配置即可工作,是新手上手 subfinder 时的"主力数据源"
二、双通道回退设计:为什么要有两条路
crt.sh 是全球最大的证书透明度(Certificate Transparency)查询服务,所有公开签发的 TLS 证书都会记录在案,因此是被动子域名挖掘的宝库。但它的"官方入口"只有 HTTP 接口,查询量大、稳定性一般。
聪明的做法是:crt.sh 本身把证书数据暴露在公共 PostgreSQL 数据库(库名certwatch)上,任何人都可以用只读账号guest直连查询。于是 subfinder 设计了SQL 优先、HTTP 兜底的双通道策略:
Run() ──▶ ① getSubdomainsFromSQL(PostgreSQL 直连) │ 有结果?── 是 ──▶ 直接返回(省掉 HTTP 请求) │ 否 └──▶ ② getSubdomainsFromHTTP(crt.sh JSON API)核心调度逻辑非常简洁(crtsh.go):先执行 SQL 查询,只要返回了至少一条数据就立即结束;只有 SQL 通道"颗粒无收"(比如网络不通、数据库访问被限制)时,才会回落到 HTTP API 通道。
三、通道一:PostgreSQL 直连
这是 crtsh 数据源最快的一条路,实现了几个值得一提的工程细节(crtsh.go):
1. 连接参数即防御
连接串中把connect_timeout设为全局超时,进入会话后再执行SET statement_timeout,从"建连"到"查询"两个环节都锁死耗时上限,防止慢查询拖垮整个枚举流程。
2. 全文检索 + 模糊匹配双保险
查询语句同时使用 PostgreSQL 的plainto_tsquery全文检索与ILIKE模糊匹配,直接在certificate_and_identities表上取NAME_VALUE字段。注释中特别说明:下游只需要NAME_VALUE,所以不再去联表解析每个证书对象的 x509 结构——这是针对大查询的性能优化,大幅降低了数据库侧的解析开销。
3. 默认 10000 条上限
如果没有指定-all参数(该开关通过 context 透传,见 pkg/runner/runner.go),SQL 会自动追加LIMIT 10000。对于常见域名,一万条证书记录通常已足够覆盖其子域名;而大站点在默认模式下也能避免一次拉回百万行数据。
四、通道二:HTTP API 回退
当 SQL 通道失败或无结果时,回退逻辑(crtsh.go)会向 crt.sh 发起一次标准 JSON 查询:
- 请求格式:
https://crt.sh/?q=%.<域名>&output=json,即按"任意前缀 + 域名"模糊搜索 - 响应是
[{id, name_value}, ...]数组,name_value中可能包含换行分隔的多个子域名(一张证书可同时关联多个名称),因此代码会逐行拆分处理 - 走的是 subfinder 统一的
Session.SimpleGet,自动继承全局超时、代理与限速配置(pkg/subscraping/agent.go)
两条通道殊途同归:产出的都是subscraping.Result结果流,通过 Go channel 异步交给上游,互不阻塞。
五、结果加工:提取、去噪与统计
无论结果来自哪条通道,都会经过同一套"流水线":
- 正则提取:pkg/subscraping/extractor.go 按目标域名编译正则,从原始文本中精准切出子域名,并过滤掉形如
foo.example.com.evil.org这类"长主机名前缀"的误报 - 小写化与去重:统一转小写后进入全局去重集合
- 统计上报:源结构体记录了
errors/results/requests/timeTaken四项指标(crtsh.go),subfinder 结束时会汇总展示各数据源的产出情况——如果 SQL 通道生效,你会看到 crtsh 的requests计数为 0,这正是双通道设计的直观证据
六、快速上手:只用 crtsh 数据源
# 仅使用 crtsh 数据源枚举 subfinder -d example.com -s crtsh # 对已有子域名递归继续挖(crtsh 支持递归) subfinder -d api.example.com -s crtsh -recursive # 使用全部数据源(含更多源,更慢) subfinder -d example.com -all七、小结
| 维度 | PostgreSQL 直连 | HTTP API 回退 |
|---|---|---|
| 速度 | ⭐⭐⭐ 全文检索,毫秒级 | ⭐⭐ 受接口限流影响 |
| 稳定性 | 依赖网络能直连 DB | 更普适的兜底方案 |
| 数据量 | 默认 LIMIT 10000 | 接口默认返回 |
| 额外依赖 | 无需 API Key | 无需 API Key |
crtsh 数据源用一份不到 230 行的代码,演示了一个数据源设计的教科书级思路:主通道追求性能,备用通道保证可用,两条通道的产出统一收敛到同一个结果管道。这种"双通道回退"模式值得任何需要对接不稳定上游服务的开发者借鉴。
📁 相关源码导航:
- 数据源实现:pkg/subscraping/sources/crtsh/crtsh.go
- 数据源接口定义:pkg/subscraping/types.go
- 全量数据源注册表:pkg/passive/sources.go
- HTTP 会话与限速:pkg/subscraping/agent.go
- 子域名提取器:pkg/subscraping/extractor.go
【免费下载链接】subfinderFast passive subdomain enumeration tool.项目地址: https://gitcode.com/gh_mirrors/su/subfinder
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考