子域接管(Subdomain Takeover)是当前网站安全领域最容易被忽视却危害极大的漏洞之一。简单来说,当你的域名下某个子域名(比如cdn.example.com、blog.example.com)的DNS记录仍然指向一个已经被注销、删除或不再使用的第三方服务(如GitHub Pages、AWS S3、Heroku等),攻击者就可以注册该第三方服务并"接管"你的子域名,用来钓鱼、传播恶意软件甚至窃取用户数据。解决这个问题的核心就两步:第一,全面检测哪些子域存在接管风险;第二,清理那些指向已失效服务的DNS记录。下面我把具体的检测方法、清理流程、自动化工具和长期防护策略一次性讲透。

一、子域接管到底是怎么发生的

子域接管的本质是DNS记录和实际服务之间的"断链"。举个实际场景:你的公司曾经在某个云平台上部署了一个内部工具,对应子域是app.example.com,DNS的CNAME记录指向了app.example.cloud-platform.com。后来这个工具下线了,云平台上的项目被删除,但你的DNS记录没人去清理。这时候攻击者只需要在同一个云平台上注册一个同名项目,就能让app.example.com直接解析到攻击者控制的页面。用户访问时完全不会察觉异常,因为域名本身是你的,浏览器地址栏显示的也是你的域名。

这种漏洞之所以危险,是因为它绕过了传统的防火墙和WAF防护。攻击者不需要攻破你的服务器,不需要拿到你的SSL证书,只需要利用一个被遗忘的DNS指向就能完成攻击。根据近年来的安全报告,子域接管在所有已知域名安全漏洞中占比持续上升,尤其在使用大量第三方SaaS服务的企业中极为普遍。

二、哪些子域最容易被接管

并非所有子域都有同样的风险。高风险子域通常具备以下特征:CNAME记录指向第三方托管平台、对应的第三方服务已被注销或项目已删除、子域长期无人维护且没有定期审计机制。常见的高风险场景包括:指向GitHub Pages的子域(用户删除仓库后)、指向Heroku的子域(应用被销毁后)、指向AWS S3的子域(存储桶被删除后)、指向Azure相关服务的子域、指向各种CDN或PaaS平台的子域。特别是那些曾经用于测试、临时项目、员工个人页面的子域,往往是最容易被遗忘的。

另外,有一类容易被忽略的情况:子域的DNS记录指向了一个已经过期或被释放的IP地址。这种情况虽然不如CNAME指向第三方平台那么典型,但同样会导致子域被他人注册和控制。所以检测时不能只看CNAME,A记录、AAAA记录同样需要纳入排查范围。

三、手动检测子域接管风险的具体方法

手动检测虽然效率不高,但对于小型网站或者初步排查非常实用。第一步,先拿到你域名的完整子域列表。你可以通过DNS区域传输(AXFR/IXFR)查询、证书透明度日志(CT Logs)查询、子域枚举工具等方式获取。第二步,逐一检查每个子域的DNS记录类型。如果是CNAME记录,记下它指向的目标地址。第三步,访问那个目标地址,看是否返回"404 Not Found"、"No such app"、"This site has been disabled"之类的提示。如果返回的是这类第三方平台的默认错误页面,基本可以确认存在接管风险。

这里有一个实用技巧:不要只看HTTP状态码。有些平台在项目被删除后会返回200状态码但页面内容是平台默认页,这种情况更隐蔽。你需要实际打开页面看内容,确认它是不是你预期的服务页面。如果页面显示的是"Domain not found"或"There isn't a GitHub Pages site here"这类信息,那就是明确的接管信号。

四、自动化检测工具与脚本方案

对于子域数量较多的网站,手动检测不现实,必须借助自动化工具。目前主流的子域接管检测工具有以下几类:

第一类是专门的子域接管扫描器,比如Subjack、SubOver等开源工具。Subjack的使用方式非常简单,它会自动对目标子域列表进行检测,识别出哪些子域存在接管风险。基本用法如下:

subjack -w subdomains.txt -t 100 -ssl -o results.txt

其中subdomains.txt是你的子域列表文件,-t 100表示并发线程数,-ssl表示同时检测HTTPS,-o指定输出文件。

第二类是集成在更大安全扫描框架中的模块,比如一些综合漏洞扫描平台会把子域接管作为一个检测项。第三类是自己写脚本。下面给一个基于Python的简单检测思路:

import dns.resolver
import requests

def check_subdomain(subdomain):
    try:
        answers = dns.resolver.resolve(subdomain, 'CNAME')
        for rdata in answers:
            target = str(rdata.target)
            response = requests.get(f"https://{target}", timeout=5)
            if "404" in str(response.status_code) or "not found" in response.text.lower():
                print(f"[VULNERABLE] {subdomain} -> {target}")
    except Exception as e:
        print(f"[ERROR] {subdomain}: {e}")

# 使用示例
check_subdomain("cdn.example.com")

这个脚本的逻辑是:先解析子域的CNAME记录,然后访问目标地址,判断是否返回错误页面。实际使用时需要根据不同平台的特征调整判断逻辑,比如GitHub Pages、Heroku、S3各自的错误页面特征不同。

五、DNS记录清理的完整操作流程

检测完成后,下一步就是清理。清理不是简单地删掉一条记录,而是需要一个规范的流程。首先,确认该子域确实不再使用。这一步很多人会跳过,直接删记录,结果导致正常业务中断。所以在删除之前,要和相关业务部门确认,最好有书面记录。其次,在DNS管理后台删除对应的记录。如果是CNAME记录,直接删除;如果是A记录或AAAA记录,同样删除。如果整个子域都不需要了,可以直接删除该子域的DNS条目。

第三步,检查是否有相关的SSL证书需要撤销。如果该子域曾经申请过SSL证书,即使DNS记录删了,证书可能还在有效期内,攻击者如果能通过其他方式让流量走到他那里,仍然可能利用这个证书。所以要到证书管理平台把对应的证书吊销。第四步,清理完成后重新进行一轮检测,确认没有遗漏。建议把清理工作纳入定期审计计划,比如每季度做一次子域安全扫描。

六、DNS记录清理的注意事项和常见坑

清理DNS记录时有几个常见的坑需要避开。第一,不要一次性大批量删除。如果你有几百个子域,不要图省事全部清空,应该分批处理,每批处理后观察业务是否受影响。第二,注意DNS记录的TTL值。删除记录后,由于DNS缓存的存在,旧记录可能还会在一段时间内生效。所以删除后要等TTL过期,或者主动刷新相关DNS缓存。第三,有些子域可能是通过CDN或负载均衡间接指向的,这种情况下你在自己的DNS里看不到直接的CNAME,需要到CDN控制台去检查和清理。

还有一个容易忽略的点:通配符DNS记录(*.example.com)的风险。如果你设置了通配符记录指向某个第三方服务,一旦该服务被注销,你所有未单独配置的子域都会变成接管目标。所以尽量避免使用通配符记录指向外部服务,如果必须使用,要确保目标服务的高可用性和持续维护。

七、建立长期防护机制

子域接管不是一次性的问题,它需要持续的治理。首先,建立子域资产台账。把所有子域、对应的服务、负责人、到期时间都记录在案,定期更新。其次,实施子域生命周期管理。任何新子域上线时必须登记,下线时必须走清理流程,不能"用完就忘"。第三,部署自动化监控。可以用定时任务定期运行子域扫描脚本,一旦发现新的接管风险立即告警。第四,在DNS管理层面做好权限控制,避免非授权人员随意添加或修改子域记录。

从更宏观的角度看,子域接管问题反映的是企业在云服务使用管理上的短板。很多企业用了大量第三方平台,但缺乏统一的资产管理和退出机制。建议把第三方服务的注销流程、DNS清理流程纳入企业的安全运营规范(SOP),让它成为日常安全运维的一部分,而不是出了事才想起来处理。

八、总结与行动建议

子域接管检测和DNS清理是一项投入不大但回报极高的安全工作。核心动作就三个:全面枚举子域、逐一检测接管风险、及时清理无效记录。工具层面可以从Subjack这类开源扫描器入手,配合自定义脚本做深度检测。制度层面要建立子域资产管理和定期审计机制。不要等到被攻击了才重视,现在就开始排查你的域名,把那些指向已失效服务的DNS记录清理干净,这是最基本也是最有效的防护手段。