公众号旧文
CT 是域名找线索,TLS 扫描从 IP 反推域名
#互联网资产测绘
很多人第一次接触互联网资产测绘时,会把Certificate Transparency(CT)日志和TLS 扫描混在一起。
因为这两种方法最后似乎都能得到:
域名、证书、IP 之间的关联。
但实际上,它们的出发点完全不同。
可以先记住一句最简单的话:
CT 更像是“从域名找线索”,TLS 扫描更像是“从 IP 反推出域名”。
这两条路径一旦结合起来,就会形成一条非常完整的资产发现链。
一、先看 CT:它更擅长告诉你“有哪些域名存在过”
当一个网站申请公开受信任的 HTTPS 证书时,证书通常会被记录到 Certificate Transparency 日志中。
证书里面最重要的信息之一,就是:
Subject Alternative Name
也就是通常说的:
SAN
例如一个证书里可能包含:
DNS:example.com
DNS:www.example.com
DNS:api.example.com
DNS:admin.example.com
那么只要这个证书进入 CT 日志,这些名字就可能被外部发现。
所以如果别人已经知道你的主域名:
example.com
就可以通过公开 CT 数据继续寻找:
www.example.com
api.example.com
admin.example.com
old.example.com
test.example.com
这就是为什么 CT 经常被用来做:
- 子域名发现
- 历史域名发现
- 证书变更追踪
- 资产梳理
- 安全测试前的信息收集
它的典型思路是:
已知域名
↓
查询 CT 日志
↓
读取历史证书
↓
读取 SAN
↓
发现更多域名
所以从方向上看,CT 是:
Domain → Certificate → More Domains
它首先解决的是:
“这个组织还有哪些域名、子域名曾经申请过证书?”
二、但 CT 通常不能直接告诉你真实源站 IP
这是一个非常容易被误解的地方。
假设 CT 日志里出现:
api.example.com
这只能说明:
某张公开证书曾经包含过
api.example.com。
它本身通常不会直接告诉你:
api.example.com
真实源站 = 45.8.173.248
尤其是在网站使用 Cloudflare、Fastly、Akamai 等 CDN 的情况下。
你正常查询:
api.example.com
DNS 很可能只会得到 CDN 的边缘 IP。
比如:
api.example.com
↓
Cloudflare
↓
104.x.x.x
172.x.x.x
真正的网站服务器可能完全藏在后面:
45.8.173.248
所以 CT 更像是:
给你提供“名字”。
但它不一定直接给你:
这个名字背后真正对应哪台服务器。
这时候,另一种方法就开始发挥作用了:
TLS 扫描。
三、TLS 扫描正好反过来:从 IP 出发找域名
假设扫描者现在不知道任何域名,只拿到了一个公网 IP:
45.8.173.248
他可以做一件非常简单的事情:
连接 45.8.173.248:443
如果这个 IP 的 443 端口开放,而且上面运行的是 HTTPS 服务,那么 TCP 连接之后就会发生 TLS 握手。
而 TLS 服务器通常需要返回自己的证书。
例如扫描者执行:
openssl s_client \
-connect 45.8.173.248:443 \
</dev/null
如果服务器直接返回了一张证书,扫描者就可以继续读取:
openssl x509 \
-noout \
-subject \
-ext subjectAltName
然后可能看到:
Subject:
CN = api.example.com
X509v3 Subject Alternative Name:
DNS:api.example.com
DNS:www.example.com
原本扫描者只知道:
45.8.173.248
现在突然多出了:
api.example.com
www.example.com
于是:
45.8.173.248
↓
443/TLS
↓
Certificate
↓
SAN
↓
api.example.com
这就是:
从 IP 反推出域名。
也可以写成:
IP → TLS → Certificate → Domain
这和 CT 的方向正好相反。
四、为什么证书会泄露域名
HTTPS 的核心问题之一,就是客户端必须确认:
“我现在连接的服务器,到底是不是我要访问的网站?”
所以服务器要给客户端发送一个证书。
证书里会写明:
这张证书可以用于哪些域名。
现在浏览器真正重点检查的是 SAN。
例如:
X509v3 Subject Alternative Name:
DNS:example.com
DNS:www.example.com
DNS:api.example.com
如果扫描者能从某个 IP 上拿到这张证书,那么实际上服务器自己就在告诉对方:
我至少和这些域名存在某种关系。
因此证书本身天然就是一种很有价值的资产元数据。
五、现实情况还要加一个 SNI
不过现代 HTTPS 还有一个非常重要的机制:
SNI,Server Name Indication。
现在一台服务器上通常不会只放一个网站。
例如:
45.8.173.248
├── a.example.com
├── b.example.com
├── api.example.com
└── admin.example.com
这些网站可能全部使用:
443
那服务器怎么知道客户端到底想访问哪个网站?
答案就是:
客户端在 TLS ClientHello 里发送 SNI。
例如:
server_name = api.example.com
Nginx、Caddy、Apache 等服务器看到这个名字后,就知道:
应该返回
api.example.com对应的证书。
所以如果直接扫描:
openssl s_client -connect 45.8.173.248:443
未必能拿到 api.example.com 的证书。
服务器可能只会返回一个:
default certificate
甚至直接拒绝连接。
六、这也是为什么“已知域名 + 已知 IP”特别强
假设通过 CT,扫描者已经发现:
api.example.com
然后又通过其他渠道怀疑:
45.8.173.248
可能是这个网站的真实源站。
现在他就可以进行验证:
openssl s_client \
-connect 45.8.173.248:443 \
-servername api.example.com \
</dev/null
这里:
-connect
决定真正连接哪个 IP:
45.8.173.248
而:
-servername
决定 TLS SNI:
api.example.com
如果服务器返回:
SAN:
DNS:api.example.com
那这条关联就非常强了。
整条逻辑变成:
CT
↓
发现 api.example.com
↓
找到疑似 IP
↓
45.8.173.248
↓
带 api.example.com 的 SNI 发起 TLS 握手
↓
服务器返回 api.example.com 证书
↓
验证 IP ↔ 域名关系
这已经不只是“猜测”。
而是服务器自己通过 TLS 响应提供了证据。
七、curl –resolve 本质上也是同一个原理
很多人测试 CDN 源站时会用:
curl --resolve \
api.example.com:443:45.8.173.248 \
https://api.example.com/
这条命令看起来比较神奇,但拆开后其实很简单。
它告诉 curl:
不要把 api.example.com 解析到正常 DNS IP
而是强制:
api.example.com
→ 45.8.173.248
但是访问 URL 仍然是:
https://api.example.com/
所以最终网络行为是:
TCP:
45.8.173.248:443
TLS SNI:
api.example.com
HTTP Host:
api.example.com
如果 45.8.173.248 真的是这个网站的源站,就可能正常返回网站。
所以:
openssl s_client -servername
主要验证 TLS 层。
而:
curl --resolve
可以继续验证 HTTP 层。
八、互联网资产搜索引擎就是大规模做这件事
自己扫描一个 IP 很简单。
真正厉害的是把这个过程扩大到整个互联网。
例如:
- Shodan
- Censys
- ZoomEye
- FOFA
这类平台会持续扫描公网地址。
它们可能扫描:
443
8443
9443
10443
等大量可能运行 TLS 的端口。
扫描后会保存:
IP
端口
TLS 版本
Cipher
Certificate Subject
Certificate SAN
Issuer
证书指纹
证书有效期
HTTP Header
HTTP Title
Server Banner
例如数据库里可能形成这样的记录:
IP:
45.8.173.248
Port:
443
TLS certificate SAN:
api.example.com
www.example.com
Issuer:
Let's Encrypt
HTTP Server:
nginx
于是以后别人搜索:
api.example.com
平台就可能反过来告诉他:
某个 IP 曾经返回过包含这个域名的证书
这也是为什么:
即使你后来已经修改 DNS,也不代表历史关联一定消失。
因为扫描平台可能已经保存过旧数据。
九、CT 和 TLS 扫描结合后,信息发现能力会强很多
单独看 CT:
example.com
↓
CT
↓
api.example.com
单独看 IP 扫描:
45.8.173.248
↓
TLS
↓
api.example.com
但是如果把两边结合:
已知 example.com
↓
CT
↓
发现 api.example.com
↓
历史 DNS / DNS / 页面 / 邮件 / 扫描
↓
怀疑 45.8.173.248
↓
带 api.example.com SNI 扫描 45.8.173.248:443
↓
拿到对应证书
↓
确认关系
这时候资产发现就形成了闭环。
所以安全研究里经常不是只依赖一个数据源。
而是:
CT
+
DNS
+
历史 DNS
+
TLS
+
HTTP
+
证书指纹
+
搜索引擎
相互验证。
十、Cloudflare 并不自动解决这个问题
很多人有一个误区:
“我的网站已经开了 Cloudflare 橙云,所以别人肯定不知道源站。”
实际上 Cloudflare 主要解决的是:
普通 DNS 查询
不会直接返回你的源站 IP。
例如:
api.example.com
↓
104.x.x.x
别人看到的是 Cloudflare。
但如果真实源站:
45.8.173.248
仍然允许所有互联网用户直接访问:
45.8.173.248:443
那么问题依然存在。
尤其如果源站根据 SNI:
api.example.com
返回正确证书和网站内容,那么一旦源站 IP 被其他方法猜到,Cloudflare 就可能被绕过。
所以真正稳妥的结构应该是:
Internet
↓
Cloudflare
↓
Origin
而不是:
Internet ───────────→ Origin
↓
Cloudflare ─────────→ Origin
也就是说,源站最好只接受:
Cloudflare → 443
而普通公网地址:
Internet → Origin:443
应该无法建立有效连接。
十一、最重要的不是“隐藏证书”,而是控制源站可达性
有时候有人发现证书 SAN 暴露域名以后,第一反应是:
那我换一张证书不就行了吗?
这只能解决部分问题。
因为别人还可以从:
- 历史证书
- HTTP 内容
- favicon hash
- 页面标题
- Server Header
- SSH Banner
- 其他端口
- 历史 DNS
- 邮件记录
- 应用指纹
继续做关联。
因此真正有效的防护原则其实很简单:
不需要公网直接访问的服务,就不要允许公网直接访问。
例如网站源站使用 Cloudflare 时:
443
只允许 Cloudflare IP
管理后台:
只允许 Tailscale / WireGuard
数据库:
只监听 localhost 或私网
内部 API:
不绑定 0.0.0.0
当互联网扫描者根本无法和服务建立连接时:
扫描 IP
↓
TIMEOUT / DROP
自然也就拿不到:
TLS Certificate
HTTP Header
Title
Banner
这比单纯试图“隐藏证书信息”可靠得多。
十二、一张图理解两者的区别
CT 的方向:
已知域名
↓
Certificate Transparency
↓
证书
↓
SAN
↓
更多域名
TLS 扫描的方向:
已知 IP
↓
连接 443
↓
TLS 握手
↓
服务器证书
↓
SAN
↓
发现域名
结合起来:
CT
域名 ───────→ 更多域名
↑ ↓
│ │
│ ↓
│ DNS / 历史数据
│ ↓
│ IP
│ ↓
└──── TLS 证书 ← 443 扫描
最终形成:
Domain
↕
Certificate
↕
IP
这就是互联网资产测绘中非常典型的一条信息关联链。
总结
如果只记住两句话就够了:
CT 的优势,是从已知域名继续发现更多域名。
TLS 扫描的优势,是从一个公网 IP 上读取证书,再反推出它可能关联的域名。
而真正强大的地方,并不是任何一种技术单独使用。
而是把:
CT
DNS
历史 DNS
TLS
HTTP
串起来。
这也是为什么一个网站即使使用了 CDN,只要源站仍然直接暴露在公网,而且还能返回真实域名对应的 TLS 证书,就仍然可能被互联网资产测绘平台建立:
真实 IP ↔ 域名
的关联。
所以从防御角度看,最重要的原则从来不是:
“怎样让别人看不到我的证书?”
而是:
哪些服务真的需要直接暴露给整个互联网?
如果答案是不需要,那么最好的处理方式,就是从网络层让它根本不可达。