接口调试新姿势

开了 SSL 抓包,有些网站反而打不开?把域名加进「跳过 SSL 代理」

已经设好了系统代理,证书也信任了,SSL 代理同样开着。

大部分 HTTPS 请求都能正常出现在抓包列表里,甚至可以直接看到请求头、请求体和响应内容。

但偏偏有几个网站打不开了。

日志里可能出现这样的错误:

PROXY_TO_SERVER_REQUEST_ERROR: Error [ERR_TLS_CERT_ALTNAME_INVALID]:
Hostname/IP does not match certificate's altnames:
Host: admin.shop-example.com. is not in the cert's altnames:
DNS:*.cdn-host.cn, DNS:cdn-host.cn

浏览器表现为页面加载失败,抓包列表里的请求也中断。

但把系统代理关掉,或者关闭 SSL 代理之后,网站又恢复正常。

这时候,问题通常不是 DevPeek 根证书没有安装。

真正发生的是:DevPeek 连接源站时,源站返回的证书与当前 Host 不匹配。

这种情况下,最简单的办法不是关闭整个 SSL 抓包,而是在 SSL 代理配置里排除这个域名,让它走 HTTPS 隧道。

本文就来看看这条错误到底意味着什么,以及为什么 Include / Exclude 两份名单需要同时存在。

适合什么情况?

如果你遇到的是下面这种情况,这篇文章正适合你:

  • 已经配置好系统代理和 DevPeek CA
  • 大部分 HTTPS 都可以正常抓包
  • 只有少数网站开启 SSL 代理后无法访问
  • 日志中出现 ERR_TLS_CERT_ALTNAME_INVALID
  • 报错里的 Host 和证书 SAN 看起来完全不是一个域名
  • 希望只放过这些特殊域名,而不是关闭整个 SSL 抓包

如果你还没有成功抓到第一个 HTTPS 请求,可以先看:

先看懂这条错误

例如:

Host: admin.shop-example.com.
is not in the cert's altnames:
DNS:*.cdn-host.cn
DNS:cdn-host.cn

这里最值得注意的是两部分。

你想访问的 Host:

admin.shop-example.com

源站实际返回的证书:

*.cdn-host.cn
cdn-host.cn

证书的 SAN(Subject Alternative Name)里没有 admin.shop-example.com

因此,Node 在连接源站时进行 TLS 证书主机名校验,发现:我正在连接 admin.shop-example.com,但你给我的证书是 *.cdn-host.cn

于是连接失败。这就是 ERR_TLS_CERT_ALTNAME_INVALID

这不是「没装 DevPeek 证书」

这是最容易搞混的地方。

如果 DevPeek CA 没有被浏览器或设备信任,通常看到的是类似:

NET::ERR_CERT_AUTHORITY_INVALID

也就是:这个证书的颁发者,我不信任。

而本文讨论的是另一种情况:ERR_TLS_CERT_ALTNAME_INVALID

它关注的是:证书里的域名,与当前连接的 Host 对不上。

所以,如果你看到 Host 是 admin.shop-example.com,证书却是 DNS:*.cdn-host.cn,继续重装 DevPeek CA 通常没有意义。

为什么只开 SSL 代理时会出问题?

理解这个问题,关键是知道 SSL 代理实际上发生了什么。

普通 HTTPS 代理连接大致是:

浏览器
   │
   │ CONNECT
   ▼
DevPeek
   │
   │ TCP 隧道
   ▼
源站

TLS 握手仍然由浏览器直接与源站完成。DevPeek 只是把连接「穿过去」。所以浏览器 ↔ 源站之间的 TLS 证书由浏览器自己验证。

而开启 SSL 代理之后,情况变成了两段 TLS:

浏览器
   │
   │ TLS
   ▼
DevPeek
   │
   │ TLS
   ▼
源站

第一段:浏览器 ↔ DevPeek。DevPeek 会动态生成对应域名的证书,并使用 DevPeek CA 签发。

第二段:DevPeek ↔ 源站。DevPeek 作为 TLS 客户端连接真实网站,并验证源站返回的证书。

因此,本文的错误发生在第二段。

为什么 CDN、WAF 特别容易碰到这种情况?

实际网络环境里,一个 IP 往往并不只服务一个网站。

例如 admin.shop-example.comapi.shop-example.comcdn-host.cnstatic.cdn-host.cn 可能最终都经过同一个 CDN、WAF 或反向代理。

正常情况下,服务器会根据 TLS 握手中的 SNI 选择正确的证书。

但如果代理链、客户端、CDN 配置或者 Host / SNI 处理存在异常,就可能出现:请求的 Host 是 admin.shop-example.com,源站返回 *.cdn-host.cn

这时候浏览器直连可能正常,但经过 SSL 中间人代理之后出现证书主机名错误。

另外,如果你看到 Host 写成 admin.shop-example.com.,末尾多了一个 .,也值得留意。这是 FQDN 的合法写法,本身并不代表错误,但某些客户端、代理或 CDN 在处理这种形式时可能存在兼容性问题。

为什么不能「失败之后自动变成隧道」?

你可能会想到一个很自然的方案:DevPeek 第一次尝试 SSL 代理失败了,那就自动改成普通 CONNECT 隧道不就行了?

问题在于,到了这里已经晚了。

SSL 代理建立的是浏览器 ↔ DevPeek 的 TLS 连接。浏览器的 ClientHello 已经交给 DevPeek 处理,DevPeek 也已经开始作为中间人连接源站。

如果这时候源站证书校验失败,原来的 CONNECT 已经不能简单地「倒退」回透明隧道。因此,隧道通常需要在建立连接之前就决定。

这也是为什么 Fiddler、Charles 等代理工具同样提供「哪些 Host 做 SSL 代理、哪些 Host 跳过」的配置,而不是等证书校验失败之后再自动降级。Charles 把这两份名单叫 Include / Exclude

DevPeek 怎么处理?

DevPeek 把 SSL 代理范围拆成两份名单:

SSL 代理这些主机,也就是 Include。默认 *,代表所有符合条件的 HTTPS Host 都允许进行 SSL 代理。

跳过 SSL 代理(隧道),也就是 Exclude。这里列出的 Host 不做 SSL 中间人代理,而是直接建立 HTTPS 隧道。

最终规则可以简单理解为:

做 SSL 代理
= SSL 已开启
  && 命中 Include
  && 未命中 Exclude

Include 和 Exclude 同时命中时,Exclude 优先。

这与参数转换里的加解密规则无关。

在 SSL 代理配置里排除这个域名

打开 DevPeek 的 SSL 代理配置

上面是 SSL 代理这些主机,下面是 跳过 SSL 代理(隧道)

例如现在 Include 是 *,而 admin.shop-example.com 开启 SSL 代理时出现 ERR_TLS_CERT_ALTNAME_INVALID,那么可以在 Exclude 中加入:

admin.shop-example.com

如果这个站点的一整个子域都存在类似问题,也可以使用:

*.shop-example.com

保存之后,后续建立的连接会按照新规则处理。已经建立的 CONNECT 不会自动变成隧道,因此修改配置后刷新页面,必要时清掉旧连接再测试。

完成标准: 该站能打开,抓包列表里对应 HTTPS 是隧道;其它仍在 Include 内的域名继续做 SSL 代理。

Include / Exclude 怎么配?

规则支持通配符,例如 **.example.com*api*api.example.com

几个典型情况:

Include Exclude 访问 Host 结果
* *.shop-example.com admin.shop-example.com 隧道
* *.shop-example.com api.other.com SSL 代理
*.example.com api.example.com api.example.com 隧道
api.example.com *.example.com api.example.com 隧道

核心原则只有一个:排除优先。 因此即使一个 Host 同时命中 Include 和 Exclude,也会走隧道。

排除名单里加入 *,则相当于把所有 HTTPS 都排除掉,也就是全部走隧道。DevPeek 会在保存前进行确认,避免误操作导致整个 SSL 抓包突然「消失」。

一个容易忽略的点:不能按 URL Path 排除

例如你可能想写 https://api.example.com/login,或者 api.example.com/v1/*

但 SSL 代理的决定发生在 HTTPS CONNECT 阶段。此时代理还没有看到 /v1/login 这样的 HTTP URL Path。

因此 SSL 代理排除只能根据 Host 等连接级信息进行匹配。也就是说:api.example.com 可以,但 api.example.com/v1/login 不是一条 SSL 代理 Host 规则。

不要把三个问题混在一起

遇到 HTTPS 抓包异常时,可以先用下面这张表快速判断:

现象 更可能是什么问题
浏览器提示「不受信任的颁发者」/ NET::ERR_CERT_AUTHORITY_INVALID DevPeek CA 没有正确安装或信任
Host 是 A,源站证书 SAN 却是完全不同的域名;直连正常,SSL 代理才失败 源站证书 / SNI / 代理链兼容问题
关闭 SSL 代理后该站仍然提示证书错误 源站自己的证书就存在问题
HTTPS 已经成功拆开,但 JSON 中仍然是密文 参数转换 / 加解密规则

尤其注意最后一种:HTTPS 已经是明文 HTTP 了,JSON 里面还是 { "data": "7a3f..." }。这不是 SSL 代理的问题,这是应用层的参数加密,可以交给 参数转换 处理。

那么,什么时候应该跳过 SSL 代理?

通常有三类情况。

1. 源站证书与 Host 存在兼容问题

例如本文的 ERR_TLS_CERT_ALTNAME_INVALID。直接把问题域加入 Exclude,让它恢复成普通 HTTPS 隧道。

2. 这个站点本来就不需要抓明文

例如 *.google-analytics.com*.example-cdn.com。这些流量只是背景请求,你并不关心它的 HTTPS 内容。把它们排除,可以减少抓包噪声。

3. 某些客户端使用了证书固定等机制

如果某个应用不适合被中间人代理,或者你根本不需要查看它的 HTTPS 明文,也可以让对应 Host 直接走隧道。

这里要注意:跳过 SSL 代理并不是「解决证书固定」,而是选择不对这部分流量进行 SSL 中间人代理。

不要为了几个网站关闭整个 SSL 代理

这是最重要的使用建议。

如果只有 admin.shop-example.com 有问题,没有必要把整个 SSL 代理关掉。也没有必要为了绕过一个站点的源站证书问题,就关闭全局的源站证书校验。后者相当于让代理不再认真验证自己连接的真实源站。

正确的思路应该是:

大部分域名
    ↓
SSL 代理
    ↓
需要明文抓包

少数特殊域名
    ↓
跳过 SSL 代理
    ↓
HTTPS 隧道

两种模式可以在同一套代理配置里长期共存。

最终可以记住这一句话

如果:直连正常 + 开启 SSL 代理后某个站点失败 + Host 与源站证书 SAN 不匹配,那么优先检查 「跳过 SSL 代理(隧道)」,而不是重新安装 CA,也不是关闭整个 SSL 抓包。

最终的判断逻辑就是:

Include
   │
   ├── 未命中 → 不做 SSL 代理
   │
   └── 命中
        │
        ├── Exclude 命中 → 隧道
        │
        └── Exclude 未命中 → SSL 代理

这样既可以保持大部分 HTTPS 的明文抓包,也不会因为少数特殊站点把整个代理配置关掉。

下一步

如果你需要继续处理接口调试,可以沿着同一条代理链继续往下:

如果只是想解决本文这个问题,通常只需要:找到出问题的 Host → 在 SSL 代理配置里排除它 → 刷新连接。

下一篇

《待整理:代理链上的断点、重发与协作》——继续聊接口联调中那些容易被代理工具「卡住」的细节。


如果你也遇到过「一开 SSL 代理,个别网站反而打不开」,欢迎 下载 DevPeek 试试在 SSL 代理配置中增加一条排除规则,也可以到 GitHub Discussions 交流你遇到的证书、CDN 或代理兼容问题。

相关文档

系列文章