如果访问 Google,收到百度的证书,会有怎样的现象发生?
时间:2025-7-8 10:15 作者:wanzi 分类: 网络
最近在学习 Wireshark 抓包,想看看 TLS 握手过程中都传了些什么,然后在做一个简单的 HTTPS 请求测试时,突然冒出了一个奇怪的想法:
如果我明明是访问
google.com
,但中间有人把请求偷偷重定向到了www.baidu.com:443
,那么服务器会怎么处理?会直接报错?还是返回一些奇怪的数据?
01 - 初步实验
为了验证这个问题,我做了如下操作:
- 用 curl 或浏览器发起请求,目标是
google.com:443
- 在本地或内网的某个网络设备上做了个「端口重定向」,比如 iptables、HAProxy
- 把所有发往
google.com:443
的请求,重定向到www.baidu.com:443
iptables 简单重定向
可以用 iptables 把目标地址为 google.com 的 443 端口请求转到百度:
先解析百度的 IP
dig +short www.baidu.com # 假设结果是 220.181.38.150
iptables 添加重定向规则(假设外网访问走 eth0):
sudo iptables -t nat -A OUTPUT -p tcp -d google.com --dport 443 -j DNAT --to-destination 220.181.38.150:443
或者直接写 IP:
sudo iptables -t nat -A OUTPUT -p tcp -d 142.250.4.113 --dport 443 -j DNAT --to-destination 220.181.38.150:443
如果是给 本地 curl 请求生效,还需要给 本地流量(lo)或 OUTPUT 链 添加。
⚠️ 注意:
这种做法只是强制把 TCP 连接发给百度,不能改变 HTTPS 协议里的 SNI 字段。curl、浏览器仍然以 google.com 为目标主机名发起 TLS 握手。
然后打开 Wireshark,看看 TLS 层的通信情况。

02 - 实验结果
非常有趣的是:
- 浏览器或 curl 的请求目标依然是 google.com
- 请求发出的 TLS ClientHello 里,SNI 字段明确写着:google.com
- 但因为 TCP 连接实际建立在 baidu.com:443,百度收到一个「要求 google.com 证书」的请求。
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLS certificate verification: CERT_NAME_INVALID
* error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
* Closing connection
curl: (60) SSL certificate problem: certificate has expired or is not yet valid
那么,百度怎么办?
百度自然不可能有 google.com 的证书,它按照惯例,返回了自己的 HTTPS 证书,证书里写着「*.baidu.com」。
于是,客户端一看:
“你给我的是 baidu.com 的证书,我要的是 google.com,证书不匹配,安全风险,连接失败!”
03 - 这是不是服务器的「错误行为」?
并不是。这正是大多数 HTTPS 服务器的标准行为。
在收到 SNI 后,服务器会:
- 查找有没有对应的域名证书
- 如果没有,就返回 默认站点的证书
- 不会因为「不知道这个域名」就直接拒绝握手
04 - 为什么不直接拒绝?
你可能会问:
“服务器为什么不直接断开连接,说:我没有 google.com 的证书?”
原因很简单:
- 按照 TLS 协议流程,握手就是要返回证书,不返回流程就不完整
- 服务器不知道客户端是不是误打误撞、是不是测试
- 所以最安全的做法是:返回自己的证书,让客户端自己决定信不信
当然,一些高安全场景,可以配置服务器直接拒绝,比如:
- Nginx 的
return 444
- Envoy 的 no-default-cert 策略
- 但这不是通用做法,尤其是大网站更倾向于保持协议兼容性
简单理解下tls协议流程:
✅ 服务器如何处理 SNI
HTTPS 建立过程的第一步是 客户端发起 TLS ClientHello,里面包含了:
- SNI(Server Name Indication):告诉服务器「我要访问哪个域名」
- 支持的加密算法
- 会话标识等
服务器拿到 ClientHello 后会:
- 检查是否有对应 SNI 的证书
-
如果有,比如:
- SNI 是
www.baidu.com
,服务器配置了baidu.com
的证书 → 返回 baidu 的证书 - SNI 是
google.com
,但服务器根本没配 google.com 的证书
- SNI 是
-
那么服务器只能:
- 返回「默认证书」 → 一般就是 第一个配置的证书,或默认站点证书
- 通常是 baidu.com 的证书
⚠️ 没有 “不给证书” 这种操作,因为 TLS 协议要求必须返回证书完成握手,除非直接断开连接(那就是拒绝服务了)。
🔍 为什么是默认证书而不是直接拒绝?
因为:
- 多数 HTTPS 服务器 是基于域名的多站点部署,比如 Nginx、Apache
- 它们无法提前知道用户会请求什么域名,只能等收到 SNI 后决定返回哪个证书
-
如果域名不匹配,它们通常:
- 仍然返回一个默认站点证书(比如 baidu.com)
- 让客户端自行决定是否继续
✔️ 这是为了:
- 保持协议兼容性
- 防止主动探测时直接暴露「服务不存在」
SNI 只是「建议」,服务器只会返回它有的证书;没有就用默认的,TLS 协议不会因为 SNI 不存在就拒绝握手,但客户端会因为证书不对而中断。
05 - 一次有趣的误会
所以,这个实验的结果也挺有趣的:
我问“google.com”是谁,百度虽然不认识,但还是礼貌地递给我一张自己的名片,客户端一看,名字不对,直接拒绝了。
06 - 小结
- HTTPS 重定向不能简单靠 TCP 层转发,TLS 层还会校验域名和证书。
- SNI 决定了服务器要返回哪个证书,而不是 TCP 的目标 IP。
- 如果证书和请求域名不匹配,客户端会报错,中间人也无法伪造。