☰
互联网资产梳理插件:子域收敛、端口探测与资产台账
2026/11/6 4:15:52 网站建设 项目流程

做互联网资产梳理的人,大概都有过这样一段经历:最初只是想搞清楚自己这边到底有多少个域名在对外提供服务,于是写了个脚本跑一遍;过了两周发现端口信息也得看,又加了一个脚本;再后来指纹识别、证书信息、归属部门都要往里塞,脚本从一个变成五个,从五个变成十几个,最后没人说得清哪个脚本是最新版,也没人知道上周跑出来的那份表格到底覆盖了什么范围。标题里提到的这款插件,本质上就是把这堆零散动作收进一个统一入口的产物——它做的事情并不神秘,就是把互联网资产梳理这条链路上的采集、识别、归集、比对串起来,让"我现在到底有哪些资产"这个问题有一个稳定的答案来源。这篇内容适合两类人看:一类是手上已经有一堆半成品脚本、想整理成体系的人;另一类是刚开始接手资产盘点工作、不知道从哪里下手的人。下面我按自己实际搭这套东西的顺序,把这个插件的结构、参数、踩过的坑和最后形成的使用习惯完整讲一遍。

1. 资产梳理为什么最后都会收敛成一个插件

1.1 脚本堆到第十个的时候,问题就不再是脚本本身了

我见过很多团队的资产梳理起点都极其朴素:一个 bash 脚本调用几个命令行工具,把结果往 CSV 里一写,完事。前三个月这套东西是好用的,因为资产规模小、跑的人只有一两个、结果也只是自己看。真正出问题是在资产规模上去之后,具体表现有三种。

第一种是口径不一致。A 同学跑的脚本用-w参数只做域名爆破,B 同学跑的脚本只用证书日志拉数据,两个人交上来的表格放在一起,字段名对不上、去重逻辑不一样,合并的时候要人工对半天。第二种是结果不可复现。脚本里写死了一堆临时文件路径和当天日期,隔一周想重跑一次对比变化,发现跑出来的东西结构都变了。第三种最要命,是没人知道边界在哪。脚本能扫什么、扫到哪一层、哪些目标是不该碰的,这些信息只存在于写脚本那个人的脑子里,人一走,这套东西就成了一颗不知道什么时候会响的雷。

插件形态解决的恰恰是这三个问题。它把参数、输出结构、目标范围都变成了显式的配置项,谁跑都一样,跑出来长什么样是固定的,边界写在配置文件里而不是脑子里。这一点听起来很平淡,但只要你在真实环境里被"这份数据是谁什么时候用什么参数跑出来的"这个问题卡过一次,就会明白它的价值。

1.2 插件形态带来的真正变化:能力和流程解耦

我一开始也觉得"插件"这个词有点被滥用了,很多所谓的插件不过是把脚本包了个壳。但用下来我发现,插件和脚本最本质的区别不在于界面,而在于它把采集能力和使用流程拆开了。

脚本是"一条线跑到底":从读目标开始,到写文件结束,中间任何一步想改都得动整条线。而插件是"注册式"的:每一类采集能力(子域发现、端口探测、指纹匹配、证书解析)都是一个独立的执行单元,主流程只负责调度和汇总。这意味着你可以在不改动主流程的前提下替换掉其中一环——比如原来用字典爆破做子域发现,后来换成用证书透明度日志加被动 DNS,只需要换掉那一个模块,其余部分完全不动。

这个特性在长期维护里的价值极高。资产梳理这件事的特点是数据源一直在变:某个被动数据源关停了、某个指纹库更新了规则格式、某个协议版本的探测方式调整了,这些都是常态。如果整条链路是耦合的,每次变动都是一次全量回归;如果是解耦的,变动被限制在一个小格子里。

1.3 这款插件的能力边界,先说清楚不做什么

在讲它做什么之前,我更想先讲它不做什么,因为这决定了你能不能在合规的前提下用它。

它做的是:给定一份你已经确认有管理权限的目标清单(域名、IP 段、组织名),把公开可获取的信息汇总起来,形成一份结构化的资产台账,并且能对比出两次盘点之间的差异。它不做的是:绕过任何访问控制、对未授权目标发起探测、对目标系统做任何形式的验证性测试。这两条线必须划得非常清楚,因为资产梳理和未授权探测在动作上高度相似,区别只在于你有没有那个权限,以及你有没有把权限证明留痕。

我在实际使用中形成的习惯是:任何一次梳理任务启动前,先在任务配置里挂一份授权说明(可以是工单号、可以是内部审批记录编号),插件会把这份说明写进任务元数据里,跟着结果一起归档。这个动作花不了两分钟,但它是把"技术动作"变成"可追溯的合规动作"的关键一步。后面所有关于参数、并发、范围的讨论,都建立在这个前提之上。

2. 三段式发现链路:从域名一路走到可读的资产条目

2.1 第一段:子域收敛,先把"可能存在的东西"列全

资产梳理的第一个动作永远是扩大已知集合。你手上通常只有几个主域名,而实际在跑的资产可能散落在几十上百个子域上,其中相当一部分是历史遗留、测试环境、外包交付物,从来没进过任何台账。

这一段插件走的是多源合并的路子,而不是单靠字典爆破。原因很实际:字典爆破的覆盖率完全取决于字典质量,而且会产生大量 DNS 请求,对权威服务器不友好,容易被限流甚至被误判。多源合并的思路是先从"别人已经公开记录过的信息"里捞,再考虑主动补充。

具体来说,我配置的源大概分四类:

数据源类型拿到的信息特点
证书透明度日志证书里登记的域名覆盖面广,纯被动,无请求压力
被动 DNS 记录历史解析关系能捞到已经下线的历史资产
公开的测绘数据域名与 IP 的关联更新有延迟,适合做交叉验证
主动字典枚举未公开的子域覆盖取决于字典,需要控速

这四类数据合起来之后,第一件事不是急着往下走,而是做归一化和去重。这一步看起来琐碎,但它是后面所有统计准确性的基础。归一化要处理的东西包括:大小写统一、去掉末尾的点、把通配符解析产生的伪记录剔掉、把明显不属于目标组织的域名(比如第三方 SaaS 平台的默认子域)标记为待确认而不是直接入库。

# 归一化与初步过滤的核心逻辑(示意) def normalize(host): host = host.strip().lower().rstrip('.') if not host or '*' in host: return None return host def is_suspected_third_party(host, owned_domains): # 不属于任何自有主域后缀的,先标记待确认,不直接丢弃 return not any(host == d or host.endswith('.' + d) for d in owned_domains)

我特别想强调"标记待确认"而不是"直接丢弃"这个设计。早期我图省事,凡是不匹配主域的统统扔掉,结果后来发现有几个业务确实用了完全不同的域名,白白漏掉了半年。现在的做法是分两栏:确认资产和待确认资产,后者不影响主台账,但每次盘点都会列出来让人过一眼。

2.2 第二段:端口与协议识别,这一步决定后面所有判断的成本

拿到域名集合之后,下一个问题是"这些域名后面到底跑着什么"。这里有一个很多人会踩的思维误区:以为端口扫描是资产梳理的核心。实际上端口扫描只是中间环节,它的输出质量直接决定了后面指纹识别的准确率,而它本身的成本又是整条链路里最高的。

插件在这一段的处理逻辑是分层递进,而不是一上来就全端口。我的配置大致是这样:

  • 第一层:只探常见 Web 端口(80、443、8080、8443 等十余个),超时设得比较短,目的是快速判断"这个东西活着没有"。
  • 第二层:对第一层有响应的目标,扩展到常见服务端口段,仍控制在合理范围内。
  • 第三层:只对明确需要深挖的目标(比如新出现的、归属不明的)做更大范围的探测,并且单独走低并发的队列。

这个分层设计的理由是成本和收益的严重不对称。全端口扫描一个 C 段,即使把并发调到很高,耗时也是小时级的,而其中 99% 的端口是关闭的,扫出来也不会增加任何资产信息。反过来,先做轻量探测把"活的"筛出来,再对少量目标做深挖,整体耗时能压到原来的十分之一不到,而有效发现几乎不损失。

有一个参数我调了很久才找到合适的值:超时时间。设太短,跨地域的高延迟目标会被误判为不可达,直接漏掉;设太长,一个不可达的 IP 会拖住整个队列。我最后的做法是分级超时——同地域目标 1 秒,跨地域目标 3 秒,并且对超时的目标做一次重试,重试仍超时才标记为不可达。这个"重试一次"的动作看起来微不足道,但实测能把误判率降下来一大截,因为很多超时是瞬时拥塞造成的。

2.3 第三段:指纹与归属,把 IP 变成人能看懂的资产

端口探通只是知道了"有个东西在那里",但台账上写"1.2.3.4:8443 开放"是没有意义的,因为没人知道那是谁的、干什么用的、出问题该找谁。这一段要解决的就是把技术标识翻译成业务语言。

指纹识别我分了三个层次,因为不同层次的稳定性和成本差别很大:

第一层是协议层特征,也就是从响应头、TLS 证书、服务 banner 里能直接读到的信息。这一层最稳定,误报率最低,因为它不依赖任何猜测。比如证书里的组织字段、响应头里的服务标识、banner 里的版本号,这些都是"目标自己说的",可信度高。

第二层是页面特征,包括标题、特定路径的响应、静态资源的路径结构。这一层准确率明显下降,因为标题可以随便写,路径可以随便改。我在这一层加了"多特征联合判定"的规则:单个特征命中只记为"疑似",两个以上独立特征同时命中才升级为"确认"。这个改动把误报压下去一大半。

第三层是归属推断,也就是判断这个资产属于哪个部门、哪个项目。这一层严格来说不是技术活,而是数据治理活。插件的做法是把 IP 段、证书组织名、域名命名规律这三类线索和内部已有的组织信息做匹配,匹配上的自动打标,匹配不上的进"待认领"池。

提示:待认领池是整份台账里最有价值的部分之一。我做过统计,新发现的资产里大概有六成最终都落在待认领池里,而这些恰恰是最容易出问题的部分——没人认领通常意味着没人维护、没人打补丁、没人监控。

3. 授权边界与扫描节奏:把梳理做成一件不越界的事

3.1 授权清单要落到目标粒度,而不是网段粒度

这一节我放在很前面讲,因为它比任何技术细节都重要。

常见的做法是拿到一份"某网段归我们管"的说明就开始扫,这在内部管理上可能是够的,但在实际操作里埋了很大的隐患:一个网段里可能混着托管服务、可能混着合作方的设备、可能混着已经从业务上摘除但还没走完下线流程的机器。你以为在扫自己的东西,实际上碰到了别人的。

我现在的做法是把授权清单做到目标粒度:每一个进入扫描队列的目标,都必须能对应到一条授权记录。具体形式可以是一张表:

字段说明
目标标识域名或 IP 段,精确到最小可授权单位
授权依据内部工单号或审批记录编号
责任人该目标的技术负责人
有效期限授权到什么时候为止,过期自动移出队列
允许动作只做被动收集,还是允许主动端口探测

这张表的最大作用是把"我能不能扫"这个判断从人脑里挪到了数据里。插件在加载任务时会先读这张表,不在表里的目标直接跳过并在日志里记一条,而不是靠人记得"这个不能碰"。有效期这个字段也很有用,我遇到过好几次资产转交的情况,老责任人早就不管了,授权过期自动失效,逼着流程重新走一遍确认,反而避免了很多扯皮。

3.2 并发、超时和重试:这三个参数决定成败

如果说资产梳理有什么"玄学"参数,那一定是并发数。调太低跑不完,调太高会被限流、被封、被投诉,中间那个甜点区还随目标规模变化。

我摸索出来的经验是按目标类型分队列,而不是全局一个并发数:

  • 对自建服务的探测:并发可以开得比较高,因为对方是自己的设备,扛得住,而且响应快。
  • 对第三方托管服务的探测:并发必须压低,一方面是人家的服务条款通常有限制,另一方面是压测别人的基础设施本身就是不合适的。
  • 对被动数据源的查询:严格按各数据源公开的频率限制来,宁可慢,也不要因为超限被拉黑——被拉黑一次,恢复期往往是几天到几周,得不偿失。

超时和重试的关系也需要理清。我的配置原则是:超时设短、重试设少、但对失败原因分类记录。具体是超时 3 秒、最多重试 1 次,然后记录失败原因(连接超时、连接被拒、DNS 解析失败、TLS 握手失败)。分类记录的价值在于事后分析:如果某一批目标的失败原因集中在 TLS 握手失败,那通常说明这批资产用了非标准配置,值得单独看一眼;如果集中在 DNS 解析失败,那多半是前面子域收敛阶段混进了脏数据。

3.3 碰到第三方托管资产时的处理原则

资产梳理里最尴尬的情况是:一个域名确实是自己的,但它解析到了第三方托管的地址上。这时候端口探测的对象实际上是人家的基础设施。

我的处理原则很简单:只做被动识别,不做主动探测。具体就是通过访问标准端口获取响应头和证书信息来判断服务类型,绝不做大范围端口扫描,绝不做任何形式的能力验证。判断依据可以提前准备好——把已知的主流托管服务商的地址段整理成一份对照表,命中就直接降级为被动模式。

这个原则听起来保守,但在实际操作中几乎没有损失。因为托管资产的服务类型本来就是已知的(要么是对象存储、要么是 CDN、要么是 SaaS 平台),你需要的只是"这个域名在用哪个平台"这个结论,而这个结论通过一次正常的 HTTPS 请求就能拿到,不需要任何额外动作。

4. 资产表怎么设计,决定了这套东西能不能长期用下去

4.1 资产唯一标识:一个看似简单但很多人做错的决定

资产表的第一件事是定义"什么叫同一个资产"。这个问题看起来 trivial,实际上决定了后面所有统计的正确性。

常见的错误做法是用IP:端口做唯一键。问题是 IP 会变——同一台机器换了地址,在你的表里就变成了两个资产、一次消失、一次新增,变更报表立刻失真。另一个常见错误是用域名做唯一键,问题是同一个域名可能对应多个服务,也可能一个服务挂在多个域名上。

我最后采用的方案是双标识:一个技术标识(服务指纹 + 证书指纹的组合),一个业务标识(归属部门 + 用途描述,人工维护)。技术标识自动生成、用于机器比对;业务标识人工维护、用于人看。两者通过一个中间表关联,允许一对多。

这个设计的实际好处在变更追踪上体现得最明显。举个具体的例子:某台服务器的 IP 从 A 换成了 B,技术标识因为证书没变而保持不变,系统识别为"地址变更"而不是"资产消失 + 新资产出现"。这两种描述在报表上看起来差不多,但对负责人的意义完全不同——前者是一个已知资产的配置变动,后者是两件需要分别核查的事。

4.2 只存快照的表一定会失控,变更流才是答案

早期我做过最蠢的一件事,是每次盘点都存一份完整快照,然后用 Excel 的比对功能找差异。资产到几百条之后,这件事就完全做不动了。

正确的做法是快照 + 变更流双写:每次盘点结束,既保存一份完整快照(用于回答"某个时间点是什么样"),也生成一份变更记录(用于回答"这期间发生了什么")。变更记录只记三件事:新增、消失、属性变更。属性变更要具体到字段级别,比如"端口 8443 从开放变为关闭"、"指纹从 A 变为 B"、"责任人从甲变为乙"。

{ "asset_id": "svc-7f3a...", "change_type": "attribute_update", "field": "tls_cert_org", "old_value": null, "new_value": "某业务线", "detected_at": "2025-01-01T00:00:00Z", "task_id": "scan-20250101-01" }

这个结构最大的价值是让"消失"这件事变得可分析。资产消失的原因有太多种:正常下线、DNS 变更、扫描失败、授权过期被移出队列。如果只记"消失了",你根本分不清是哪种。所以我在变更记录里强制带上task_id,能追溯回那次具体任务,再结合那次任务的失败统计就能定位原因。

4.3 标签体系和责任人字段,别等到出问题才补

标签这件事,我的建议是宁可先粗后细,也不要一开始就设计一套复杂的分类法。因为资产梳理的初期,你对资产的实际构成是没有概念的,拍脑袋设计出来的分类体系多半用不上。

我现在的标签分三类,加起来不超过十五个值:

  • 来源标签:这条资产是怎么被发现的(被动数据源、主动枚举、人工录入)。这个标签用于评估发现能力的覆盖度。
  • 状态标签:在用、待确认、疑似废弃、已下线。这个标签驱动后续的处理流程。
  • 归属标签:部门或项目。这个字段允许为空,为空即进入待认领池。

责任人字段我建议设成必填项之外的"强建议"字段,也就是允许为空但要在报表里高亮。原因很现实:很多资产在发现的时候确实找不到责任人,强行必填只会逼着人随便填一个。

注意:待认领池要定期清理,但不能粗暴地"超时未认领就删除"。我吃过的亏是删掉了一批看起来没人管的资产,半年后发现有两条是关键的外部对接入口。现在的做法是超时后转入"归档"状态,仍在表里,但不出现在日常报表中,年度盘点时再捞出来看一次。

5. 实测里最耗时间的几个坑

5.1 泛解析和通配符,能把结果撑大十倍

子域收敛阶段最容易踩的坑就是泛解析。有些域名的 DNS 配置成任意子域都返回同一个地址,这时候字典枚举会把字典里每一个词都"命中",几千条结果瞬间灌进来,全是假的。

识别方法其实不复杂:随机生成几个明显不存在的子域去查询,如果都能解析成功,说明存在泛解析。但处理方式有很多种,我试过两种:

第一种是直接放弃该域名的主动枚举,只用被动数据源。简单粗暴,但会漏掉真实存在的子域。

第二种是对比解析结果:泛解析通常会把所有子域指向同一组 IP,所以把解析结果按 IP 分组,指向那组"泛解析 IP"的一律标记为疑似,只保留指向不同 IP 的记录。这个方法能救回大部分真实子域,代价是要多做一轮分析。

我最后两种都用:主域有泛解析时切到第二种模式,同时降低该域的枚举优先级。另外还有一个细节——泛解析的处理结果要缓存,同一个域不要每次都重新探测,否则每次盘点的前几分钟都在做重复劳动。

5.2 CDN 让端口扫描结果完全失真

第二个坑更隐蔽。一个域名解析到 CDN 地址,你对这个地址做端口扫描,扫出来的开放端口是 CDN 边缘节点的,跟你的实际资产毫无关系。更糟的是,你可能因此得出"这台机器开放了二十多个端口"的错误结论,然后在报表里体现出来,误导后面所有人。

识别 CDN 的办法是看解析结果的地址段和证书信息。地址段可以用公开的 CDN 地址段清单比对,证书信息更直接——CDN 边缘节点的证书通常是通配符证书,组织字段往往是 CDN 服务商而不是你的组织。

识别出来之后怎么处理?我的做法是分层记录:在资产表里把这个域名标记为"经 CDN 接入",记录 CDN 服务商信息,然后跳过端口探测,转而去找它的源站线索。源站线索的获取是另一件事,通常来自历史 DNS 记录、证书透明度日志里的历史条目、以及内部登记信息。这一步不做自动化,因为误判代价太高——把别人的 IP 当成自己的源站去探测,是很严重的问题。

5.3 指纹误报:标题里的关键词骗过了规则

指纹识别阶段的误报,我踩过最典型的一次是规则里写了某个中间件的特征关键词,结果大量使用该中间件做默认错误页的站点全部命中。更离谱的是有些站点的 404 页面标题里就带着这个关键词,等于所有路径都命中。

这类问题的根因是规则只匹配了内容,没有匹配上下文。修复思路有三条,我现在的规则里全都用上了:

修复手段具体做法效果
限定匹配位置只在响应头、特定路径的响应体中匹配,不在任意页面匹配消除大部分偶然命中
加排除规则对已知的默认页、错误页特征做排除消除默认页误报
多特征联合单个特征只记疑似,两个以上才确认大幅降低误报率

第三条的代价是召回率下降,因为有些服务确实只暴露一个特征。所以我的做法是保留两级结果:确认级进主台账,疑似级进待确认池,人工过一遍。这个流程听起来低效,但实际上待确认池每次也就几十条,扫一眼的成本很低,比起被误报污染主台账之后再回头洗数据,划算太多。

6. 把插件接进日常:定时、增量与结果呈现

6.1 全量和增量的节奏怎么排

资产梳理不是一次性任务,但也不是越频繁越好。频率太高,一是成本上去了,二是变更流里全是噪音,真正重要的变化被淹没。

我现在的节奏是三层:

每周一次轻量盘点,只做被动数据源收集和已有资产的存活确认,不发现新资产,目的是及时发现"资产消失"这类异常。每月一次完整盘点,跑全链路,包括子域收敛、端口探测、指纹识别,产出正式台账和变更报表。每季度一次深度盘点,在完整盘点基础上加上更大范围的端口探测和人工复核待认领池。

这个节奏的好处是成本可控,而且不同频率的盘点回答的是不同的问题:周度回答"有没有东西掉了",月度回答"有没有新东西进来",季度回答"这份台账还准不准"。

6.2 结果怎么呈现,决定了有没有人真的会看

这一条是我踩过最深的坑。早期我把结果做成一个几百行的表格发出去,结果没人看。后来改成三层呈现,情况才好转:

第一层是摘要,只有一行字:本次新增 N 条、消失 M 条、属性变更 K 条,其中待认领 X 条。这一行放在最前面,让人三秒钟判断要不要往下看。

第二层是分类明细,按归属部门分组,每组列出新增和消失的条目。这一层给各部门负责人看,他们只关心自己那部分。

第三层是完整台账,全量数据,附带每次任务的元信息(时间、参数、授权依据)。这一层是归档用的,平时不打开。

这个分层看起来是排版问题,实际上是信息分发问题。同一份数据,不同角色需要的粒度完全不同,把所有人塞进同一张表,结果就是所有人都觉得难用。

6.3 一个容易忽略的收尾动作:把本次任务的元信息写进归档

最后分享一个很小的习惯,但它救过我很多次。

每次盘点任务结束,插件会自动生成一份元信息文件,内容包括:任务 ID、执行时间、使用的配置文件版本、目标清单的哈希值、授权依据的引用、以及本次任务的统计摘要。这份文件跟结果数据放在一起,文件名带上日期。

为什么这么重要?因为半年后有人拿着某份数据问你"这个结论是怎么来的",你能在三十秒内翻到当时的配置和目标范围,而不是靠回忆。资产梳理这类工作的成果,可信度很大程度上取决于可追溯性,而可追溯性不是靠文档写出来的,是靠每次任务自动留痕攒出来的。

我自己在实际操作中的体会是,这套东西真正的门槛不在技术,而在愿不愿意把流程上的每一步都显式化。参数写进配置文件、授权写进任务元数据、变更写进变更流、结论写进分层报表,每一条单独看都是琐碎的体力活,但攒起来之后,你就有了一个别人能接手、能复核、能长期跑下去的东西。插件本身只是把这些显式化的动作变得省力一点,真正决定这套资产梳理能不能立住的,还是那些看起来最不技术的部分:目标范围有没有说清楚、数据来源有没有标注、待确认的东西有没有人跟进。

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

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

立即咨询