Charles抓包HTTPS显示unknown?证书与SSL Pinning排查指南

发布时间:2026/10/17 14:26:01
Charles抓包HTTPS显示unknown?证书与SSL Pinning排查指南 搞移动端开发的人几乎都绕不过抓包这一步。前阵一个朋友发消息问我用 Charles 抓手机包的时候为什么有的包能正常抓到有的却显示 unknown他说自己对着同一个 App 翻来覆去刷大部分接口都能看到 JSON 响应可个别接口在列表里只剩一个带 unknown 标识的深色条目点开以后没有 URL、没有请求头、没有响应体。这个问题我刚上手 Charles 时也撞见过而且当时还以为是手机代理没配好折腾了大半宿。后来把原理弄清楚了才发现答案一直都很明确网上的说法是“HTTPS 要装证书”但真正的原因往往比这一句话更细。这篇文章不打算从零教你怎么配置代理而是把所有可能让某个包显示成 unknown 的原因一条条捋清楚再给你一套可以直接照着做的排查步骤。不管你是刚入门的 Android 开发、正在做前后端联调还是偶尔要看看线上接口的测试同学后面这些内容应该都能帮你省下不少时间。1. 先搞清楚 Charles 的工作原理再看 unknown 从哪来1.1 HTTP 是明文Charles 当然看得懂抓包之所以能成功本质上是手机把流量交到了 Charles 手里。你在 Wi-Fi 设置里填代理 IP 和端口之后App 发出的每一个 HTTP 请求都会先到电脑上的 Charles 进程然后由 Charles 转发给真正的服务器。这个“转发”的动作非常关键。HTTP 协议是明文传输的请求行、请求头、请求体都没有加密Charles 作为一个中间代理完全可以在这个转发过程中把完整报文复制一份给你看。所以你抓到的 HTTP 接口URL、Headers、参数、JSON 响应体都能清清楚楚展示出来这也是很多人对抓包的第一印象好像只要代理配好什么都能看。但这里有个容易被忽略的事实Charles 能解密 HTTP不是因为什么黑魔法而是因为协议本身就没有加密。它只需站在客户端和服务器之间把流量原样过一遍。到了 HTTPS 这里情况就完全不同了。1.2 HTTPS 包CONNECT 隧道后面的黑盒HTTPS 不是一个单独的协议而是 HTTP 跑在 TLS/SSL 加密层之上。手机上的 App 要和服务器建立 HTTPS 连接时虽然也要先经过 Charles但事情变得复杂了。第一步客户端会发给 Charles 一个 CONNECT 请求意思是“喂我要和某个域名加端口的服务器建立一条隧道你帮我搭个桥之后的数据你别动”。这个 CONNECT 请求本身是明文所以 Charles 能看到目标域名和端口比如api.example.com:443。关键在第二步。隧道建立之后客户端和服务器之间开始进行 TLS 握手。如果 Charles 没有在这个环节介入那么隧道里流动的全是加密后的密文Charles 作为一个“管道工”只能看到一大堆看不懂的二进制数据。这时候 Charles 会怎么标记这一条流量如果它完全无法解析就会直接显示为unknown。你点进去能看到的大概只有目标主机和端口其它什么都看不了。简单来说对 Charles 而言unknown 就是“我确认这条连接是从你这台手机发出去的但我没能解密它”。1.3 “unknown” 这个词只代表 Charles 没能解密很多人看到 unknown 第一反应是网络问题或者 App 有问题其实都不对。unknown 不是报错它只是一个状态标识代表 Charles 未能成功介入 TLS 握手自然也就没有拿到可以解密会话的钥匙。TLS 握手的简要流程是客户端先发送 ClientHello里面写明支持的加密套件和希望访问的域名SNI之后服务器返回 ServerHello 和自己的证书客户端验证证书后双方再通过一系列密钥交换算出同一个会话密钥。Charles 如果想解密 HTTPS就必须在这中间扮演“假服务器”的角色客户端来握手时Charles 不是把请求转发给真实服务器而是自己先回应一个证书。这个证书是 Charles 自己生成的如果客户端信任了它也就是手机里装了 Charles 的根证书双方就能继续协商密钥Charles 在密钥协商结束后便能解密所有往来数据。如果客户端不信任这个证书握手会立刻失败客户端通常会表现出请求失败或一直转圈Charles 这边则留下一个没有解密能力的 unknown 条目。提示判断一个包是不是因为“没解密”而变成 unknown最简单的方法是看 Charles 左边列表里是否只剩下 CONNECT 请求或者一行 host:port。如果连域名都看不到说明问题大概率出在 TLS 介入失败而不是域名解析失败。把原理说清楚以后下面就可以按“三家分锅”的思路来排查了。2. 三家分锅证书、SSL 代理规则、应用校验2.1 最常见证书没装或没打开完全信任第一个锅也是最常见的锅是手机根本没有信任 Charles 的根证书。Charles 自带一个根证书用来生成每个网站对应的“假证书”。你需要在计算机上先安装 Charles 的根证书再把它装进手机。很多教程会告诉你“在手机浏览器里打开 chls.pro/ssl 下载安装”但这只是第一步。重点提醒一下iOS 用户装完描述文件以后还必须去“设置 - 通用 - 关于本机 - 证书信任设置”里面把 Charles CA 打开完全信任。这一步很多教程不会写漏掉之后 Charles 依然会显示 unknown。Android 的情况更麻烦。Android 7.0 之后系统默认不信任用户自己安装的 CA 证书只有目标 SDK 版本较低的 App 才会兼容用户证书。也就是说你把证书装进手机浏览器可能能用但很多正经 App 根本不会用它结果就是你看到某个域名的包始终 unknown。2.2 次常见SSL Proxying 规则没加全第二个锅是 Charles 的 SSL Proxying 规则没配置或者配置得不够全。Charles 不是装完证书就会自动解密所有 HTTPS 流量你必须在Proxy - SSL Proxying Settings里添加需要解密的域名和端口规则。如果你把这个页面完全空着或者只填了某个具体域名那么其它域名的 HTTPS 包就会保持 unknown。很多第一次用 Charles 的人会把 Host 填成www.example.com、端口填 443 这种精确规则结果同一个 App 里换了一个子域名就又开始 unknown。在做全面调试的时候我通常建议直接加一条* : 443先把最常见的 HTTPS 端口全覆盖。等确认问题后再逐步收窄到具体域名。注意 Host 和 Port 是分开填的两列很多人会在这里填错格式。2.3 最难搞应用做了证书校验第三个锅是 App 自身做了证书校验行业内通常叫 SSL Pinning。这种情况最棘手因为它和 Charles、和手机系统都没有直接关系。SSL Pinning 的意思是App 在代码里写死了它信任的服务器证书或公钥。即使你往手机里装了 Charles 的根证书App 依然只认自己内置的那张服务器证书看到 Charles 发来的“假证书”时会直接拒绝握手。表现出来就是你证书装好了、SSL Proxying 也开了但某个 App 的所有请求全部 unknown或者整个页面干脆无法加载。银行类、支付类、大厂的 App 基本都是这种策略。遇到这类 App首先不要怀疑自己的抓包步骤这属于 App 安全策略的一部分。如果是你自己开发的 App可以在 debug 包里程时关闭 Pinning或者用一个专门的测试包。如果是第三方 App就需要通过 hook 等方式绕过校验但这已经超出了“配证书”的范畴且只建议在你有合法授权的前提下使用。2.4 容易被忽略非标准端口与 UDP/QUIC最后一种情况很多人栽过跟头但从未想到过App 根本不走 443 端口或者压根不是 TCP 协议。有些 App 为了防抓包或者因为历史原因HTTPS 服务跑在 8080、8443、9090 这种自定义端口上。你的 SSL Proxying 规则只加了*:443它自然不在覆盖范围内Charles 就显示 unknown。排查办法很简单看看列表里 unknown 条目后面的端口号再把 SSL Proxying 规则加上那个端口即可。至于 UDP 上的 QUIC/HTTP3那是另一个层面的问题。Charles 默认的抓包机制建立在 TCP 代理之上UDP 流量它根本不会完整接手。如果你发现某个 App 的部分流量在 Charles 里彻底消失而系统网络层面又能看到 UDP 报文那基本可以判断是 QUIC 或自定义 UDP 协议。这种流量不是 unknown而是“不可见”。3. 完整实操把 unknown 变成可读包3.1 确认代理链路是否通先看这个浅浅的连接很多人在调整证书之前应该先确认手机流量到底有没有经过 Charles。我见过太多案例折腾半天发现手机走的是 4G/5G 网络跟电脑根本没处在同一个局域网Charles 当然什么都看不到。先做三件事。第一手机和电脑连到同一个 Wi-Fi。第二在手机 Wi-Fi 的代理设置里填写电脑的局域网 IP 和端口 8888。第三在电脑上打开 Charles 的Proxy - Proxy Settings确认勾选了 HTTP Proxy。之后随便打开一个网页看 Charles 里会不会立刻出现流量条目。如果你看到大量流量进来但有些显示 unknown那说明链路是通的问题在解密层面。如果连一条流量都没有优先检查电脑防火墙是不是把 8888 端口堵了或者手机代理 IP 填错了。3.2 在两套系统上正确安装证书确认链路通之后再处理证书。电脑端先装一份打开 Charles菜单栏选择Help - SSL Proxying - Install Charles Root Certificate然后到系统钥匙串里把证书设为始终信任。电脑端证书主要是为了让 Charles 代理桌面端浏览器流量时不会被浏览器拦下来抓手机包时其实用不到但建议还是装上后面做题省事。手机端分系统操作。iOS 的流程先是手机浏览器访问chls.pro/ssl下载描述文件然后去“设置 - 已下载描述文件”安装装完以后一定不要忘了去“设置 - 通用 - 关于本机 - 证书信任设置”把 Charles CA 底下的开关打开。iOS 如果不做这最后一步系统并不认为这个证书是受信任的TLS 握手照样失败。Android 的流程手机浏览器访问同样的地址下载证书然后到“设置 - 安全 - 加密与凭据 - 安装证书”中选择 CA 证书选择用户凭据完成安装。装完之后最好到“信任的凭据 - 用户”里确认能看到 Charles CA。Android 7.0 以上的目标 App 默认不信任用户证书这一步属于已知限制后面单独说怎么绕。3.3 配置 SSL Proxying 并添加精准匹配证书装好、信任开关打开接下来要告诉 Charles 它可以去解密哪些域名。打开Proxy - SSL Proxying Settings先把Enable SSL Proxying勾上。然后在 Locations 区域点击 Add按你的目标添加规则。命令格式是 Host 和 Port 两列Host 填*Port 填443就能覆盖绝大多数 HTTPS 流量。如果 App 用了自定义端口就把那一行再复制一条Port 改成实际端口。如果 App 的所有请求都直连某个 IP而不是走域名那么 Host 也可以直接填那个 IP 地址。我习惯在初次调试项目时直接加*:443看到流量后再针对重点域名做精细化配置。因为你写太多精确规则漏掉任何一个子域都会让人误以为抓包失败。注意Host 里的*是通配符不是让你随手填一个假的域名。很多人把 host 填成*:443一整串这就是完全搞错了列的含义规则不会生效。3.4 右键 unknown 项临时开启解密有一种操作很多人不知道在 Charles 列表里选中一个 unknown 条目然后右键选择Enable SSL Proxying。Charles 会自动帮你把这条流量的 Host 和 Port 加入 SSL Proxying 规则。然后你回到 App 里重新触发一次请求就能看到原本 unknown 的条目被解密变成完整的 HTTPS 请求。这个操作的好处是精确、直接适合目标域名不明确或者不确定端口的场景。我当时处理那个朋友的 unknown 问题用的就是这一招。他在 Charles 里右键某个 unknown 条目Charles 自动加了规则刷新页面后绿色的 JSON 包立刻出现。需要提一句右键开启解密只对“Charles 能感知到但没解密”的连接有效。如果 App 根本没走 Charles 代理或者握手已经被 App 自己拦截右键也不会生效。3.5 遇到校验型 App 该怎么办如果你把证书、SSL 规则都配好了某个 App 的请求还是 unknown那基本可以确认它是校验型应用。这种情况下正路有两条。第一条针对你自研的 App在 build.gradle 或者对应的网络层配置里为 debug 版本关闭证书校验或者放宽网络安全策略。具体做法是在 Android 的network_security_config.xml里给 debug 构建加一个信任用户证书的配置开发阶段可以临时信任 Charlesrelease 版本恢复严格校验。iOS 同理用 NSURLSession 的 delegate 在开发阶段绕过拦截校验。第二条针对第三方 App只能借助 hook 工具绕过其 Pinning 逻辑。这类工具本身是合法的安全研究工具但请不要用它去干任何越界的事情。如果你只是调试自己手机、自己设备范围内的应用社区里有很多资料可以参考如果是商业软件的逆向注意遵守相关规则和授权边界。4. 排查实录从数据看到的现象倒推原因4.1 只看到 IP 和端口域名全没了一个很典型的现象Charles 左边明明有流量但显示的是111.222.333.444:443这种格式而不是api.example.com:443。你以为是 DNS 解析问题其实不是。产生这个现象的原因通常是两类。一类是 App 直接写死了服务器 IP不走域名这种情况下 TLS 握手里没有 SNICharles 自然不知道域名只能显示 IP。另一类是 App 使用自定义 DNS 或者内部网络代理获得的域名解析结果只能拿到 IP。处理办法把这个 IP 填到 SSL Proxying 规则里而不是填域名。如果你确定请求走的是域名但 Charles 只显示 IP可以检查一下是不是开了 Charles 里的某个域名映射功能或者手机的 DNS 设置了特殊解析。4.2 证书信任了但部分页面仍失败这种情况最多见于混合内容页面App 一部分接口走正常的 HTTPS 443 端口另一部分走 WebSocket 或者流量被换成 QUIC。所以你看到“有的包能抓到有的 unknown”而且各自还很有规律。先说 WebSocket。App 先发起一个普通的 HTTP GET 请求带有Upgrade: websocket头服务器返回 101 状态码表示切换协议。之后双方就在这个 TCP 连接上持续收发数据帧Charles 对这个通道默认只能看到握手之前的请求后续帧不会以 HTTP 请求的形式呈现很多就直接归类到 unknown 或 WebSocket 分类下。再看端口规律。如果 unknown 条目清一色集中在某个端口比如 8443那就是 SSL Proxying 规则漏了端口。直接在设置里补一条*:8443就能解决。4.3 解出来的响应全是乱码和二进制还有一种让人摸不着头脑的情况unknown 的问题解决了包也确实被解密了但是响应体看过去全是乱码。先别急着怀疑解密失败。很多后端接口为了节省流量会用 gzip、brotli 压缩响应体或者用 protobuf 这类二进制序列化格式。Charles 原样显示这些压缩后的字节自然就是乱码。你可以把响应切换到 Hex 视图看是否真是一堆字节也可以尝试在 Charles 的 View 菜单里手动选择 JSON 来查看。如果是 protobuf还得配合对应的 schema 才能解析。这类包其实不算 unknown但容易让人误以为“还是没有解密成功”。我的判断习惯是如果 Charles 里能看到完整的请求头和状态码说明解密已成功展示层的问题不影响调试。4.4 处理 HTTP/2、WebSocket 与 QUIC最后把新协议单独说一下。HTTP/2 基于 TCPCharles 是可以解密的。不过由于 HTTP/2 的二进制分帧特性Charles 展示内容和 HTTP/1.x 有些差别响应头分布在 Decoded 页签下很多人不熟悉会误以为抓到的包不完整。其实该有的细节都在。WebSocket 和 HTTP/2/3 不一样它一旦切换协议就是纯二进制帧。Charles 新版本支持显示 WebSocket 的收发明文帧但如果 App 发送的是经过压缩或者自定义编码的数据表现依然是无法阅读。这种请配合其它客户端工具做协议分析。QUIC/HTTP3 走 UDPCharles 默认的 TCP 代理机制对它无效。如果你确定 App 在手机上启用了 HTTP/3一个临时馊主意是想办法让服务器端返回的 Alt-Svc 头降级为 HTTP/2或者干脆在调试设备上禁用 UDP 443 端口让流量强制退回 TCP。这个思路在不少调试场景里都有用。最后分享一点个人经验。我现在每次抓包都按固定顺序走先看手机代理有没有生效再看电脑和手机两端的证书是否完整信任接着确认 SSL Proxying 规则覆盖了目标域名和端口最后才去怀疑 App 是不是做了 Pinning。这个顺序看上去简单但能把最容易踩的坑提前排掉。尤其是 iOS 的“证书信任设置”开关很多人装完描述文件就以为完事了其实还差最后一下Android 那边则最容易卡在用户证书不被高级别 App 信任。如果你把这些步骤全走了一遍某个包依旧 unknown那大概率不是 Charles 坏了而是这个 App 在传输层做了文章。与其半夜删了重装再试不如按上面几条逐项自查基本十分钟内能把问题定位到具体环节。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询