☰
子域名信息查询与外部资产测绘:从探测到资产清单
2026/10/31 15:09:42 网站建设 项目流程

做资产梳理这行的朋友大概都有过类似经历:接手一个项目,台账上写着三十来个域名,结果一轮子域名信息查询跑下来,后端暴露出来的入口有三百多个,其中一半以上没人说得清是谁维护的。子域名信息查询这件事听起来只是"查一查有哪些子域",实际上它是整个外部资产测绘里投入产出比最高的一环——不需要接触目标业务,不需要复杂环境,靠公开数据加字典就能把一张隐藏的资产地图铺开。它解决的核心问题是信息不对称:主域名是明面上的,子域名才是那些被遗忘的测试环境、临时上线系统、第三方托管入口的聚集地。这篇内容写给三类人:负责资产台账的运维同学、做安全自查的工程师、以及想把这个流程工程化的开发者。下面我把整套思路、参数、踩过的坑都摊开讲,能直接抄的部分我会写清楚。

1. 先搞清楚子域名查询的价值边界

1.1 从"一个主站"到"一张资产地图"

很多人对子域名的理解停留在www、mail、blog这几个常见前缀上,实际上一个运营超过五年的业务域名,子域名规模往往和业务复杂度成正比。市场活动页会开临时子域,测试环境会开test/uat/staging,移动端会开app/m/wap,接口层会开api/open/gateway,还有各种外包团队交付时留下的、命名毫无规律的三级四级域名。这些入口的共同特征是:创建时没人觉得需要登记,创建后没人负责回收。

所以子域名信息查询的真正产出不是一份"域名列表",而是一张资产地图。地图的价值在于它把分散的记录聚合成可比较的对象:哪些域名解析到了内网地址段、哪些挂在第三方云服务上、哪些的 TLS 证书已经过期三个月、哪些页面的标题写着"系统维护中"却依然对外可达。我在实际项目里见过最典型的情况是,某个业务线三年前做活动开了一个子域,活动结束后页面没下线,后台管理入口还留着默认路径——这类问题只有靠系统性的查询才能发现,靠人工回忆是不可能的。

从工程角度看,一张好的资产地图至少要包含四个维度:域名本身(完整 FQDN)、解析事实(A/AAAA/CNAME 记录)、服务特征(HTTP 状态码、页面标题、响应头里的技术栈线索)、归属判断(自有 IP、云托管、CDN 加速)。缺了最后一维,你拿到的就是一堆无法定责的字符串。

1.2 谁需要做、在什么前提下做

先说前提,这个必须放在最前面:子域名信息查询只应该对自己拥有或已获得明确书面授权的资产进行。原因很实际——主动爆破环节会对目标权威 DNS 产生真实查询压力,被动收集环节虽然只读公开数据,但把结果与业务系统关联分析,本质上已经属于资产测绘行为。未经授权的测绘在很多地区的法规里都是明确禁止的,这不是技术问题,是责任问题。

合规的做法是:查询范围以书面授权清单为准,清单里写清楚根域名、允许使用的技术手段、允许的并发上限、数据留存期限。我建议在项目启动时就把这份清单落到文档里,别嫌麻烦,等到需要向业务方解释"为什么上周 DNS 查询量涨了十倍"的时候,这份文档就是唯一的依据。

需要做这件事的角色大致分三类。第一类是资产管理员,目的是把台账补全,把"僵尸资产"清理掉,这类需求偏重完整度和归属判断。第二类是安全自查人员,目的是找出对外暴露但缺乏防护的入口,偏重服务特征识别和风险排序。第三类是开发者,可能是为了做域名迁移、证书统一管理、或是给监控系统补全探针列表,偏重解析事实和变更追踪。三类人的工具链其实高度重合,差别只在最后的输出排序和处置动作上。

提示:任何一次查询开始前,先确认根域名当前是否使用泛解析。这个判断会直接决定你后面几万条结果里有多少是噪音,也会决定你字典策略要不要调整。

2. 原理拆解:子域名是怎么被一条条"捞"出来的

2.1 被动收集:不碰目标,从公开数据里捡

被动收集的核心思想是"别人已经替我查过了"。互联网上存在大量公开的、包含域名信息的数据集,我们只是把这些数据集里的记录按根域名过滤出来。常见的来源有这几类:

证书透明度日志。这是目前性价比最高的单一来源。所有公开信任的 TLS 证书签发记录都会被写进日志,而证书里的 SAN 字段(Subject Alternative Name)经常一次性列出一批域名。很多运维在申请证书时为了省事,会把同一业务线的所有子域塞进一张证书,等于主动把资产清单公开了。这类数据的好处是真实发生过,不是猜出来的。

搜索引擎索引。站点被收录时,URL 里的主机名就是现成的子域名。按site:语法配合常见前缀做筛选,能捞到一批。缺点是有滞后,且只覆盖被索引过的页面。

公开的 DNS 扫描数据集。有一些长期运行的互联网测量项目会定期全量扫描并公开解析结果,从中可以筛出属于目标根域的记录。这类数据的价值在于覆盖长尾——那些字典里没有、搜索引擎也没收录的奇怪命名,往往能在这里出现。

代码托管平台的公开仓库。配置文件里硬编码的域名、CI 脚本里的部署地址、前端代码里的 API 基地址,都是高价值线索。这一路要注意只读取公开可见的内容。

邮件与 DNS 配置记录。SPF 记录里常会列出授权的发信服务器子域,DMARC 的rua地址、DKIM 选择器、MX 记录指向的主机名,都能反推出内部命名规范。我见过一个案例,从 SPF 记录里翻出了三个从未在字典里出现过的区域性发信子域。

被动收集的工程要点是去重和来源标记。同一个域名可能从五个来源出现,你要记录"来源=CT日志+搜索引擎",因为来源数量本身就是一个可信度权重——单一来源出现的记录,后面验证时要多留个心眼。

2.2 主动探测:字典、DNS与速率控制

主动探测就是拿一份候选名字列表,逐个拼成候选名.根域名去做 DNS 查询,能解析出记录的就认为存在。原理简单到不能再简单,难点全在工程细节上。

第一是字典质量。一份好的字典不是几万个随机单词堆起来的,而是分层组织的:通用层(www、mail、api、cdn、static)、业务层(按行业特点,比如电商会有pay、order、cart,教育行业会有course、exam、study)、地域层(bj、sh、gz之类的拼音缩写,或者us、hk之类的区域码)、环境层(test、dev、uat、staging、pre、sandbox)、数字与序列层(1到999,v1、v2,app1到app20)。分层的好处是可以按需组合,先跑通用+环境层拿到高置信度结果,再决定要不要投入算力跑长尾。

第二是解析器选择。直接用系统默认的递归解析器跑十万次查询,大概率会被上游限速甚至临时拒绝服务。靠谱的做法是自建一个本地递归解析器并开启缓存,或者准备一组解析出口做轮询。缓存命中率会很惊喜——很多字典里的高频词在不同根域下解析结果一致,本地缓存能显著压低实际外部查询量。

第三是并发与超时。这两个参数必须一起算。假设字典 8 万条,单次查询平均耗时 60 毫秒,并发 100,那么理论吞吐是 100 / 0.06 ≈ 1666 QPS,跑完需要 80000 / 1666 ≈ 48 秒。但现实里 DNS 查询的耗时分布极不均匀,绝大部分在 20 毫秒内返回,少数超时请求会拖到 3 秒。如果超时设得太宽松,几个慢查询就能把并发槽位占满,整体吞吐反而下降。我的经验值是:超时设 2 到 3 秒,并发从 50 起步,观察失败率再往上加。失败率(超时占比)超过 5% 就说明压力过大或者解析器扛不住了,要降并发。

# 示意命令,参数名以你实际选用的工具为准 # 字典爆破:100 并发,2 秒超时,结果写入 brute.txt dns_brute -d example.com \ -w ./dict/level1.txt \ -c 100 \ -t 2 \ -r ./resolvers.txt \ -o ./out/brute.txt

注意:这段命令里的工具名和参数是示意写法,不同实现差异很大。真正要抄的是参数之间的关系,不是具体的字母。

2.3 证书透明度:最容易被忽略的高产来源

单独把证书透明度拎出来讲,是因为它值得单独做一轮。CT 日志的查询接口支持按域名做前缀匹配,返回的是证书条目,你需要从name_value字段里把域名一个个拆出来。这个源的两个特点是:新鲜度高(证书一签发就能查到)、命名真实(证书里的名字是运维自己填的,不是猜的)。

实操中有几个细节。一是要处理通配符证书,*.example.com这种记录只说明根域下有通配符,不指向具体子域,但它的存在本身就是个信号——说明该域可能开了泛解析,后面要重点验证。二是要做时间窗口控制,CT 日志的数据量随时间线性增长,如果不限定起始时间,一次查询可能返回几十万条历史记录,其中大量是早已下线的。我通常只取最近 12 到 24 个月的记录,兼顾完整度和效率。三是要注意证书里可能包含不属于目标组织但共用同一张证书的域名,比如虚拟主机服务商把多个客户域名塞进一张证书,这类记录必须靠后续的解析验证来剔除。

同步一下:如果目标根域有多个,比如主域加几个品牌域,CT 查询要按根域分别跑,然后合并去重。合并时保留"首次出现时间",因为那往往对应资产的实际创建时间,对后续的归属判断很有帮助。

2.4 泛解析和 CDN:两个最大的噪音源

这两件事如果不处理,你拿到的结果基本没法用。

泛解析指根域配置了通配符记录,任何随便什么.example.com都能解析成功。这时候你用字典跑出来的"结果"会是一份和字典长度完全一致的列表——看起来收获巨大,实际全是假的。检测方法很简单:生成 10 到 20 个高熵随机字符串(比如x7k2m9q1、zz8f3a6b),拼成子域去解析。如果全部解析成功,且返回的 IP 集合高度重合,基本可以判定为泛解析。

判定为泛解析之后不要直接放弃,要做的是记录泛解析 IP 集合,然后在后续结果里反向剔除:凡是解析结果落在泛解析 IP 集合内的记录,全部标记为低置信度。但这里有个坑——真实的子域也可能恰好解析到同一组 IP,尤其是在用统一入口做反向代理的架构下。我的处理方式是保留这些记录但打上标记,同时在验证阶段用 HTTP 层做二次确认:泛解析返回的通常是统一的默认页或 404,而真实子域会有各自不同的响应内容、不同的证书、不同的标题。这个差异就是区分依据。

CDN带来的是另一种误导。很多子域会返回CNAME指向某个 CDN 厂商的域名,你顺着解析只能拿到 CDN 边缘节点的 IP,拿不到真实源站。这时候不要试图去"绕过"——那既无必要也不合适。正确做法是把这类记录单独归类为"托管型资产",记录 CDN 厂商、证书信息、HTTP 响应特征,这些信息对资产盘点同样有价值。真正需要关注的是那些没有走 CDN、直接解析到自有 IP 段的子域,它们往往意味着更直接的暴露面。

3. 工具选型:不追求全能,追求能串起来

3.1 被动收集层的选型逻辑

被动收集工具这个方向选择很多,我的建议是先想清楚三件事,再决定用什么。

第一,你要的是"广度"还是"可控性"。有些工具内置了几十个数据源,一次调用能把公开数据几乎榨干,代价是耗时很长(几分钟到十几分钟不等),而且部分数据源需要各自的 API 凭据。有些工具只做单一数据源,胜在快、稳定、可编程。项目初期我倾向于先用广度型工具跑一轮拿基线,后面做周期性监控时换成单源工具,跑得快、diff 更清晰。

第二,凭据管理怎么做。多源聚合类工具通常需要配置一批第三方服务的 API Key,这些 Key 有的免费额度很低,有的按调用量计费。工程上要把凭据集中放在环境变量或配置文件里,别硬编码进脚本。同时要记录每个源的消耗,避免月底发现某个源的额度被打爆。

第三,输出格式是否统一。理想的输出是每行一个 FQDN 加来源标记,方便后续sort -u和awk处理。如果工具输出的是带 ANSI 颜色的表格或者 JSON 嵌套结构,前期多花十分钟写个转换脚本,后面能省很多事。

# 示意流程:多源被动收集后做标准化归并 passive_scan -d example.com --sources ct,engine,dataset -o ./out/raw_passive.txt # 统一小写、去空白、去重、按字母序排列 tr 'A-Z' 'a-z' < ./out/raw_passive.txt | tr -d ' \r' | sort -u > ./out/passive.txt wc -l ./out/passive.txt

3.2 爆破层与字典的匹配

爆破工具的差异主要在性能上,功能层面反而趋同。选型时看三个指标:单机 QPS 上限、是否支持自定义解析器列表、是否支持通配符自动检测。第三点很关键,很多工具会在启动时自动做泛解析探测,省掉你自己写检测脚本的功夫。

字典这块我想多说两句,因为它是决定上限的东西。网上流传的"十万级子域名字典"质量参差不齐,里面大量是重复项、拼写错误、以及从别的行业硬搬过来的词。更靠谱的做法是自己维护一份分层字典:

层级内容示例规模建议使用阶段
通用高频www、mail、api、cdn、static、img200 到 500每轮必跑
环境标识test、dev、uat、staging、pre、sandbox50 到 100每轮必跑
业务功能pay、order、user、admin、report300 到 800每轮必跑
地域区域bj、sh、gz、hk、us、sg50 到 200视业务覆盖
技术组件git、jenkins、wiki、monitor、log100 到 300每轮必跑
数字序列1 到 999、v1 到 v201000 左右按需
拼音组合业务相关的拼音全拼与首字母视情况按需

分层字典的实际用法是:第一轮只跑前三层(约一千条),几十秒出结果,快速建立基线;第二轮加技术组件和地域层;第三轮才上数字序列和拼音组合。这种渐进式策略的好处是,绝大多数情况下前两轮已经能覆盖 80% 以上的真实资产,后面的长尾投入产出比很低,可以根据项目时间预算决定要不要做。

3.3 验证层:把"能解析"变成"确认存在"

能解析只是第一步。一个子域解析成功,可能是真的有个服务在那跑,也可能是一条遗留的 DNS 记录、一个已下线的 CNAME、或者泛解析的产物。验证层的任务就是把这三种情况分开。

验证手段按成本从低到高排:DNS 层看记录类型和 IP 归属,TLS 层看证书是否有效、SAN 里有哪些名字,HTTP 层看状态码、响应头、页面标题、favicon 哈希。这三层跑完,一条记录的可信度基本就确定了。

HTTP 验证要注意协议和端口。很多子域只开 HTTPS 不开 HTTP,或者只在非标准端口上提供服务。验证时至少覆盖http://和https://两种协议,端口先测 80 和 443,如果 DNS 记录里有明确的其它端口线索再补测。并发不要开太高,HTTP 探测比 DNS 查询重得多,几百并发很容易把目标或自己的出口打满,起始值建议 20 到 30。

# 示意:批量探测并抓取关键特征 http_probe -l ./out/passive.txt \ -ports 80,443 \ -threads 25 \ -timeout 8 \ -title \ -tech-detect \ -json -o ./out/probe.json

4. 完整实操:从零到一份可用的资产清单

4.1 环境与目录规划

动手之前先把目录结构定下来,这个习惯能救命。我习惯按"阶段 + 时间戳"组织:

workdir/ ├── dict/ # 字典,按层级分文件 │ ├── level1.txt │ ├── level2.txt │ └── level3.txt ├── resolvers.txt # 解析器列表 ├── out/ │ ├── 20250101_passive.txt │ ├── 20250101_brute.txt │ ├── 20250101_merged.txt │ ├── 20250101_probe.json │ └── 20250101_final.csv └── log/ └── 20250101_run.log

带日期前缀的好处是永远知道哪份结果是哪次跑的,做 diff 的时候一目了然。解析器列表单独放,方便随时替换;日志单独存,出问题能回溯到具体是哪一轮、哪个参数导致的异常。

环境上有两点准备:一是确认本机对外的 DNS 查询不会被本地网络策略拦掉,可以先手动查几个已知域名验证连通性;二是确认磁盘空间,一次完整跑下来,中间文件加上 HTTP 响应体(如果保留的话)可能占几百 MB 到几个 GB,别到时候写满。

4.2 第一轮:被动收集与初步归并

第一轮目标只有一个:在尽可能短的时间内拿到一份基线。我的做法是并行跑被动收集和第一层字典爆破,两条线互不干扰。

被动收集按 4 到 8 分钟的超时上限跑,超时就收工,已有的结果先拿去用。这一步要注意的是不要把多个根域混在一起跑,每个根域单独出一份结果,最后再合并。原因不同根域的泛解析配置不同,混着跑后面剔除噪音会很麻烦。

第一层字典爆破用level1.txt,几百条,几十秒完成。这一步的结果可信度最高,因为通用高频词的命名在任何组织里都高度相似。

两份结果合并后做第一次去重,同时统计两个数字:被动来源的独立记录数、爆破来源的独立记录数、两者的交集。交集的大小能反映一件事——如果交集几乎为零,说明被动源的覆盖方向和你字典的方向完全不同,这很正常(CT 日志偏向真实业务命名,字典偏向通用命名);如果爆破结果远超被动结果,说明这个组织的命名比较规范,字典命中率高,后面值得加大字典投入。

# 合并、去重、按字母序输出 cat ./out/passive.txt ./out/brute_l1.txt \ | tr 'A-Z' 'a-z' \ | grep -E "^[a-z0-9._-]+\.example\.com$" \ | sort -u > ./out/merged_l1.txt # 看总量和交集 comm -12 <(sort -u ./out/passive.txt) <(sort -u ./out/brute_l1.txt) | wc -l

那个grep -E过滤不能省。被动源里经常混进格式不对的字符串,比如带路径的 URL、带端口的地址、甚至是被截断的半个域名,不过滤干净后面每一步都要处理异常。

4.3 第二轮:字典爆破与并发参数估算

第二轮把level2.txt和level3.txt加上,规模跳到一个量级。这时候参数就没法拍脑袋了,得算。

先估总查询量:假设合并后的字典是 5 万条(已去重),要跑 1 个根域,总查询量 5 万。再估单查询耗时:本地递归解析器开启缓存后,命中缓存的查询在 1 到 5 毫秒,未命中的要看上游,平均下来我按 15 毫秒估。那么单线程 QPS 约 66,开 100 并发理论 QPS 是 6600——这个数字明显不现实,因为瓶颈很快会转移到解析器的处理能力和网络出口上。

更靠谱的估算方式是从实际可承受的外部查询速率倒推。自建递归解析器在普通云主机上稳定跑 800 到 1500 QPS 是没问题的,保守按 800 算,5 万条查询需要 50000 / 800 ≈ 63 秒。这个数字才是计划依据。如果外部查询速率只有 200 QPS(比如受限于上游服务商的限速),那 5 万条就要 250 秒,四分钟出头。两种情况都能接受,真正要避免的是未估算就直接开到几百并发,结果被上游判定为异常流量,导致整个出口被封一段时间。

并发值我一般这么定:并发数 = 目标外部 QPS × 平均查询耗时(秒)。按 800 QPS 和 0.015 秒算,并发 12 就够了;但为了防止慢查询把吞吐拖死,实际会开到 50 到 100,留足余量吸收超时请求。这个公式背后的逻辑是利特尔法则,理解了就能自己调,不用记具体数字。

# 示意:带泛解析检测与速率控制的爆破 dns_brute -d example.com \ -w <(cat ./dict/level2.txt ./dict/level3.txt | sort -u) \ -c 80 \ -t 2 \ --rate-limit 800 \ --wildcard-detect \ -r ./resolvers.txt \ -o ./out/brute_l2.txt

跑的过程中盯两个指标:实时 QPS和超时率。QPS 明显低于设定值,说明解析器成了瓶颈;超时率超过 5%,说明并发或速率给大了。这两个指标在多数工具的输出里都能看到,看不到就自己加个统计脚本,每 10 秒打印一次。

4.4 第三轮:验证、指纹与去噪

前三轮收集完,把结果合并去重,进入验证阶段。这一步的目标是把一份"可能是资产"的列表,变成一份"确认是资产"的表格。

第一道验证是 DNS 层。把合并后的列表全量重解析一遍,记录每条的 A 记录、AAAA 记录、CNAME 链。这里会剔除掉一批"第一次查到有、现在没有了"的临时记录——DNS 缓存和短暂的记录变更都会造成这种假阳性。同时统计每个 IP 被多少条域名指向,指向数量异常高的 IP(比如一个 IP 被两百个域名共享)大概率是泛解析或负载均衡入口,标记出来。

第二道验证是泛解析回流。把前面记录的泛解析 IP 集合拿出来,凡是解析结果完全落在该集合内的记录,全部打上wildcard标记。注意是"完全落在",如果一条记录解析到泛解析 IP 之外的地址,说明它有自己的配置,要保留。

第三道验证是 HTTP/TLS 层。对保留下来的记录做协议探测,抓这几样东西:最终状态码、重定向链、页面标题、Server和X-Powered-By之类的响应头、favicon 哈希、TLS 证书的签发者和有效期。这几样组合起来,一条记录的性质基本就明确了。

去噪的判定规则我整理成了表格,实际跑的时候直接套:

现象判定处理方式
解析到泛解析 IP 集合内泛解析产物标记低置信度,不进入正式清单
CNAME 指向 CDN 厂商域名托管型资产单独归类,记录 CDN 厂商
解析成功但 HTTP 全部超时可能已下线标记待复核,下一轮再看
返回统一默认页、标题相同可能是反代兜底按 IP 分组后人工抽检
证书过期超过 90 天疑似废弃优先级调高,值得清理
页面标题含"测试""维护中"非生产环境重点标注,风险排序靠前

这个表格不是教条,不同架构的组织会遇到不同情况。比如用统一网关做入口的架构,大量子域解析到同一组 IP、返回同一套响应头,这时候按 IP 分组就失去意义了,得改成按证书 SAN 分组或者按业务命名前缀分组。

4.5 输出规范与持续监控

最终产出我建议用 CSV,字段固定下来,方便导入表格工具或者直接进数据库:

字段说明示例值
fqdn完整域名api.example.com
record_type记录类型A / CNAME
resolved_ip解析结果203.0.113.10
cname_chainCNAME 链lb.example-cdn.net
http_status最终状态码200
title页面标题接口网关
tech_stack技术栈线索nginx / 某框架
cert_expire证书到期日2025-08-12
source数据来源ct,engine,brute_l2
confidence置信度高 / 中 / 低
first_seen首次发现时间2025-01-01

字段定好之后,周期性重跑才是这套流程真正产生价值的地方。我的做法是每周跑一次轻量版(只跑被动收集加第一层字典),每月跑一次完整版。两次结果做 diff,输出三类变化:新增域名、解析变更、服务下线。新增域名要立刻确认归属,因为新上线的资产往往配置不完整;解析变更要关注从自有 IP 切到 CDN 的情况,那可能是迁移;服务下线可以做清理建议,把 DNS 记录一并回收。

# 简易 diff:找出本次新增的域名 comm -13 <(sort -u ./out/20241201_final.txt) <(sort -u ./out/20250101_final.txt) \ > ./out/new_domains.txt

diff 的噪音控制也有讲究。泛解析的 IP 集合每周可能在变,如果不把泛解析记录先剔掉就做 diff,你会看到几百条"新增",全是假的。所以 diff 之前必须先执行去噪,顺序不能反。

5. 常见问题与排查速查

5.1 结果数量忽多忽少

这是最常见的困惑。同一套字典,上周跑出 400 条,这周跑出 80 条,第一反应是工具坏了,其实八成是下面几个原因。

上游解析器被限速或临时拒绝。表现是整体耗时没变但结果骤减,日志里能看到大量超时。解决办法是换解析器出口,降并发重新跑一遍关键部分。

本地缓存污染。上一次跑的时候某些域名解析成功,缓存还在,这次直接命中,看起来"有结果";但如果上一次是泛解析状态,缓存里存的其实是泛解析 IP,这次泛解析关了,缓存没失效,结果就不一致。排查方法是查一条已知记录,看返回的 TTL 是不是异常小。

字典文件被改动了。多人协作时最容易出这种事,有人往字典里加了内容或者删了行。养成习惯:每轮跑之前先wc -l和校验和,记录到日志里。

根域的 NS 变了。换了 DNS 服务商之后,新服务商的解析行为、限速策略、泛解析默认配置都可能不同。这种情况要重新做一遍泛解析检测。

5.2 泛解析干扰的识别与剔除

判断是不是泛解析,用随机串测试就够了,但要注意测试的严谨性。随机串至少要 10 个,长度 8 位以上,字符集混合大小写字母和数字,避免和真实命名撞上。全部解析成功才算泛解析,有一部分失败说明用的是"部分泛解析"或者基于规则的解析(比如只对特定前缀返回记录),这种情况要单独分析规则。

剔除的时候有个容易翻车的地方:泛解析返回的 IP 可能不止一个。有的配置会轮询返回一组 IP,你只记录了一个,剔除的时候就会漏。解决办法是测试时多查几次,把返回的 IP 全收集起来,形成完整集合再比对。

还有一种更隐蔽的情况:泛解析返回的 IP 和某个真实子域返回的 IP 完全相同。这时候单看 DNS 没法区分,必须靠 HTTP 层的内容差异。我遇到过一整个网段都是这种配置,最后是靠页面标题和证书 SAN 才把真实资产挑出来的。

5.3 超时、限速与误报的处理

超时率高的时候,第一反应往往是加并发,这是错的。超时率高的本质是系统在告诉你"压力太大了",加并发只会更糟。正确的顺序是:先降速率,看超时率是否下降;如果降了还是高,换解析器;换了还高,检查本地网络出口是否有丢包。

误报的处理要分类型。DNS 层误报(记录存在但服务已下线)靠 HTTP 验证剔除。内容层误报(服务在线但不是目标资产,比如共享 IP 上的其他站点)靠证书和页面特征判断,看证书 SAN 里有没有目标根域。命名层误报(字典词恰好是别人的子域,比如某些通用词被第三方注册)这种其实很少见,真遇到了就在字典里加排除项。

还有一个隐性问题:HTTP 探测的误报来自默认站点。很多服务器配置了默认虚拟主机,任何指向该 IP 的域名请求都会返回同一个页面。判断方法是给一个不存在的子域发请求,看返回内容和目标记录是否一致。一致就说明是默认站点兜底,这条记录要么标记低置信度,要么直接排除。

5.4 问题速查表

症状可能原因排查动作处理建议
结果量与字典长度完全一致泛解析随机串测试记录 IP 集合后剔除
耗时正常但结果为零字典路径错 / 根域拼错检查文件与参数修正后重跑
大量超时并发或速率过高看实时 QPS 与超时率降并发至 50 起步
HTTP 全部 403有访问控制看响应头与证书保留记录,标注受限
标题全相同默认站点兜底用不存在子域对照标记低置信度
CNAME 指向陌生域名CDN 或第三方托管查 CNAME 目标归属归类为托管型
两次结果差异巨大缓存 / 字典变动对比字典校验和固化字典版本

6. 几句实在的踩坑体会

6.1 字典质量决定上限,工具只决定速度

这个结论是我踩了几年坑才认下来的。刚开始做的时候沉迷于找"更强的工具",换来换去发现结果差不多,瓶颈从来不在工具。后来把精力转到字典维护上,效果立竿见影。具体做法是:每做完一个项目,把确认存在的、字典里原本没有的命名补进去,标注来源行业。攒了两年,字典从一万条涨到四万多条,其中大概三成是自建的,命中率比通用字典高出一大截。

字典维护还有一个技巧:记录命名的"风格"。有的组织喜欢用短横线连接(user-center),有的喜欢下划线,有的喜欢连写(usercenter),还有的喜欢加数字后缀。同一个组织内部风格通常是一致的,发现一种风格之后按这个风格批量生成变体,比盲目扩字典有效得多。

6.2 数据时效比完整度更重要

一开始我追求"一次跑全",字典越大越好、数据源越多越好,跑一次要半小时。后来发现,资产梳理这个场景里,上周的数据往往比三个月前的完整数据更有用。原因很实际:新增资产才是风险集中区,老资产大多已经被反复检查过了。

所以现在的策略是高频轻量、低频全量。每周一次快速跑,覆盖被动源加第一层字典,十分钟内完成,重点看新增。每月一次全量,把长尾补齐。这个节奏下,真正需要人工确认的记录数量很少,大部分变化都能自动化处理。

6.3 合规是底线,不是免责声明

最后说这个,因为它比技术重要得多。我见过太多人把"我只查了公开数据"当成免责理由,实际上主动爆破阶段的 DNS 查询压力是实打实作用在别人系统上的,被动收集后的关联分析也可能触及不该碰的范围。合规的做法前面已经说过:书面授权、明确范围、限定手段、记录留存。这几件事做了不费什么力气,不做的话,一旦出问题,技术上的所有努力都归零。

还有一个实操层面的建议:查询结果要当作敏感数据管理。一份完整的资产清单,包含内部系统命名、IP 段、技术栈信息,泄露出去的风险不比漏洞小。存储加密、访问控制、定期清理,该做的都要做。我在项目结束后的习惯是把中间文件清理掉,只保留最终清单和日志摘要,清单本身按授权约定的期限保存。

这套流程跑顺之后,一个中等规模的根域,从零到一份可用的资产清单大概两个小时,其中人工介入的时间不到二十分钟。剩下的大部分时间机器在跑,你可以去做别的事。真正花时间的从来不是查询本身,是接下来对结果的判断和处置——那部分没有工具能替你做。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询