在移动与后端开发中,Charles 是最常见的调试代理之一。很多工程师会关心一个核心问题:Charles 是如何"看"到 HTTPS 的明文的? 理解其原理能帮助你快速定位抓包失败、SSL 错误或握手异常的根因。本文从底层协议和操作流程讲清 Charles 抓包 HTTPS 的原理、常见限制(Pinning、mTLS、HSTS、HTTP/2 等),并给出实操排查步骤与工具组合建议(在无法用 Charles 解密时,如何用 USB 直连工具如 Sniffmaster 做补充验证)。
一、核心原理:中间人(MITM)+ 自签 CA 的工作方式
- TCP 与 TLS 的基本链路
- 客户端对服务器发起 TCP 连接(默认 443);之后进行 TLS 握手(ClientHello/ServerHello),建立对称会话密钥,用于加密后续 HTTP 内容。
- 代理如何插入(CONNECT)
- 浏览器/应用在配置 HTTP 代理时,对 HTTPS 请求发送
CONNECT host:443 HTTP/1.1
。代理收到后会与客户端建立一个隧道(TCP 层)。 - 若不解密,代理仅做透明通道(看到 CONNECT),无法读取应用层明文。
- 浏览器/应用在配置 HTTP 代理时,对 HTTPS 请求发送
- Charles 的 MITM 解密流程
- Charles 在接到 CONNECT 后,不是直接透传,而是与客户端完成一个 TLS 握手:Charles 用自生成的、以 Charles 根 CA 签发的"伪造"服务器证书,向客户端呈现。
- 同时 Charles 以真正的服务器为上游建立另一个 TLS 连接,从上游拿到明文后把数据转发给客户端(用两段独立的 TLS:客户端↔Charles、Charles↔服务器)。
- 要让客户端接受这张伪造证书,必须在客户端安装并信任 Charles 的根证书(CA),否则会报证书不信任错误。
简而言之:Charles 通过"做第二个服务器"和"做第二个客户端"来完成解密,它在中间做了双向的 TLS,会话终止与重建。
二、关键技术点与实现细节
- 证书签发与主机名映射:Charles 根据请求的 Host 动态生成证书(Common Name/SAN 包含目标域名)。
- SNI(Server Name Indication)处理:在与上游建立连接时,Charles 传递客户端的 SNI 保证上游返回正确证书。
- HTTP/2 与多路复用:Charles 支持将上游的 HTTP/2 流量以可读形式展现在工具里,但实际解密仍基于两段 TLS。需注意某些客户端对 ALPN 的期望会影响兼容性。
- 证书链与中间证书:Charles 所签发的伪证书必须建立完整链路(伪证书 → Charles 根),客户端需信任根证书并允许该根作签发者。iOS 还需要在"证书信任设置"中手动开启完全信任。
三、为什么有时候 Charles 抓不到或解密失败?
- 证书未安装或未完全信任 (最常见)
- iOS 除了安装证书,还要在设置里手动信任。Android 不同 ROM/版本证书安装方式也各异。
- 应用启用 SSL Pinning
- App 在代码或库层校验证书指纹/公钥(Public Key Pinning),直接拒绝 Charles 的伪造证书。
- 双向认证(mTLS)
- 服务端要求客户端证书,Charles 作为中间人若没有客户端私钥就无法完成上游握手。
- HSTS / Public Key Pinning(HPKP)策略
- 浏览器或平台策略可能阻止中间人证书被接受。HPKP 已少用,但 HSTS 会影响初次跳转策略。
- 企业透明代理或网络干预
- 公司网络的中间设备可能已经操作或替换证书链,导致你的代理链路异常。
- 非标准端口 / 非 HTTP 协议
- 某些应用不走系统代理或使用原生套接字,Charles 无法截获。
四、实操:如何配置与调试 Charles HTTPS 抓包(步骤)
- 在电脑启动 Charles,记下监听端口(默认 8888)。
- 在 iOS 设备 Wi-Fi 设置中手动配置 HTTP 代理为 Charles 的 IP:端口。
- 在设备浏览器打开 Charles 提供的证书安装页(如
chls.pro/ssl
),下载并安装根证书。 - iOS:去 设置 → 通用 → 关于本机 → 证书信任设置,将 Charles CA 打开为完全信任。
- 在 Charles 中开启 SSL Proxying,添加需要解密的域名(或全局
*
)。 - 触发 App 或浏览器请求,观察是否能看到明文请求/响应。
命令级检查(排错):
perl
# 测试代理能否接收请求
curl -v -x http://<charles_ip>:8888 https://example.com/
# 查看上游证书
openssl s_client -connect example.com:443 -servername example.com
五、遇到 Pinning / mTLS / 真机限制时的补救办法
当 Charles 无法解密(尤其是 App 启用 SSL Pinning 或要求客户端证书),有几条可行路径:
- 在测试环境使用测试证书或关闭 Pinning(开发首选)
- 让后端在测试环境接受测试 CA,或在测试构建里禁用 Pinning,便可用 Charles 完整解密与修改流量。
- 代理持有上游客户端证书(高风险,仅限受控环境)
- 如果可以导出客户端 p12,理论上可在代理上配置为上游证书,但这涉及私钥管理与合规风险。
- 改用底层抓包 + 协议分析
- 用
tcpdump
/ Wireshark 抓取 TLS 报文,分析 ClientHello/Alert 等来定位握手错误(不能看到明文但能定位原因)。
- 用
- USB 直连真机抓包(当代理无解时的"最后一招")
- 某些场景下,App 不走系统代理或 Pinning 无法绕过,Charles 无法工作。此时可使用能 USB 直连 iOS 的抓包工具(例如 抓包大师 Sniffmaster )直接获取设备流量并导出 PCAP。Sniffmaster 在工程实践中常被用来:
- 精准按 App 抓取,减少噪声流量;
- 在不少 Pinning 或 mTLS 场景下提供可分析的握手流程与(在测试可行时)明文;
- 导出 PCAP 与 Wireshark 联合使用,结合服务端日志完成定位。
- 这种方式不依赖设备端安装代理证书,适用于无法改 App 的生产/灰度场景(前提:合规授权与测试环境控制)。
- 某些场景下,App 不走系统代理或 Pinning 无法绕过,Charles 无法工作。此时可使用能 USB 直连 iOS 的抓包工具(例如 抓包大师 Sniffmaster )直接获取设备流量并导出 PCAP。Sniffmaster 在工程实践中常被用来:
六、常见故障与快速排查清单
- 无流量显示:确认设备代理是否指向正确 IP & 端口;防火墙是否阻挡。
- 只看到 CONNECT:证书未安装或未信任,或 Charles 未启用 SSL Proxying。
- 浏览器能抓、App 不能:怀疑 Pinning 或 App 未使用系统代理;尝试用 Sniffmaster 做直连抓包。
- 解密后看到乱码:检查
Content-Encoding
(gzip/br)、HTTP/2 分帧或二进制协议(protobuf 等)。 - 上游握手失败:用 openssl 检查服务器证书与 SNI;用 Wireshark 分析 TLS Alert。
理解 Charles 的 HTTPS 原理,就是理解它作了两次 TLS 握手并在中间解密重放。对大多数开发和测试场景,Charles 足够高效。但面对 SSL Pinning、mTLS 或应用自建套接字时,Charles 会受限。工程化的做法是把工具链组合起来:
- 日常开发:Charles / Proxyman 做第一线调试;
- 自动化与批量修改:mitmproxy;
- 底层握手/网络问题:tcpdump + Wireshark;
- 无法改 App 或 Pinning 场景:USB 直连抓包工具(如 Sniffmaster)+ Wireshark 分析。
把这些工具按照"从高层到低层、从易到难"的流程使用,能把绝大多数 HTTPS 抓包问题工程化地解决。