Charles 和 Proxyman 的 HTTPS 解密配置教程

Charles 和 Proxyman 的 HTTPS 解密配置教程

Charles 和 Proxyman 的 HTTPS 解密配置教程


Charles 和 Proxyman 的 HTTPS 解密配置教程


在 Android 开发里抓包,最常见的情况不是配代理,而是配完代理之后满屏的红色叉号。Charles 的列表里显示 <unknown>,Proxyman 的 Flow 窗口里弹出 SSL Handshake Failed,这时候你知道问题出在 HTTPS 解密上,但按照网上教程点了一圈菜单,手机浏览器里证书也装了,回到应用里依然握手失败。这种情况在 Android 7.0 之后变成了常态,因为 Google 从 Nougat 开始收紧了用户证书的信任策略,而大多数抓取工具的教学文档还停留在 Android 6.0 的时代。Charles 和 Proxyman 作为目前开发者最常用的两款桌面抓包工具,它们的证书体系、代理架构和 Android 适配方式有本质差异,理解这些差异比记住几个点击步骤更重要。


抓包解密的核心:自签根证书与中间人代理


Charles 和 Proxyman 的 HTTPS 解密逻辑都是典型的中间人代理(MITM)。当手机把代理指向运行着 Charles 或 Proxyman 的电脑时,应用发出的 HTTPS 请求实际先到达桌面端的代理软件。代理软件需要向手机应用呈现一个由自己签发的服务器证书,然后自己再去和真实服务器建立连接。为了让手机应用信任这个伪造的证书,必须在系统或应用层面预置该代理软件的自签根证书。


这里有个关键细节:Charles 使用 Java 原生的 keytool 体系管理其根证书,证书存储在应用内部的 Java KeyStore 中。你可以在 Charles 的菜单 Help > SSL Proxying > Save Charles Root Certificate 中把它导出为 .pem.cer 格式。Proxyman 则更接近现代 macOS 应用的实现,它的根证书生成后导入 macOS 系统钥匙串,随后可以通过 Certificate > Install Certificate on This Mac 或导出到移动设备。两者的证书格式虽然都是 X.509,但默认导出编码和文件名处理不同,这在 Android 端安装时会导致一些微妙的兼容性差异。


对于 Android 平台来说,系统对证书的校验极其严格。Android 从 7.0(API 24)开始,默认不再信任用户手动安装到 Settings > Security > User credentials 里的 CA 证书。这意味着,你把 Charles 或 Proxyman 的证书下载到手机,点击安装,系统提示“已安装”,但你的 targetSdkVersion 大于等于 24 的应用根本不会把它纳入信任链。于是 OkHttp 或 HttpURLConnection 在握手阶段就会抛出 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found,对应到 Charles 里就是一条 Client SSL handshake failed - Remote host closed connection during handshake,Proxyman 里则显示 The client failed to establish a secure connection


Charles 的证书体系与配置路径


Charles 是 Java 写的跨平台应用,官网 https://www.charlesproxy.com/,单用户许可证 50 美元,买断制,可免费试用 30 天。它的代理功能极其成熟,但 UI 和操作逻辑带着浓厚的 Java Swing 年代感。要用 Charles 解密 HTTPS,第一步不是去手机装证书,而是先打开 Proxy > SSL Proxying Settings,勾选 Enable SSL Proxying,然后在 Include 列表里添加 __PLACEHOLDER_ITALIC_0__ 或者至少 *:443


很多初学者在这里踩坑:Charles 默认不会解密所有 HTTPS 流量,它只解密你明确配置的主机。如果你只加了 __PLACEHOLDER_ITALIC_0__:*,虽然这会让 Charles 的 CPU 占用稍微上升,但在现代开发机器上基本可以忽略。


手机端的配置步骤看似简单,实际坑很多。把手机 Wi-Fi 代理设为 Charles 运行的机器 IP 和端口 8888(默认),然后在手机浏览器访问 chls.pro/ssl 下载证书。这个地址是 Charles 内置的证书分发页面,会根据你当前的 Charles 版本返回对应的根证书。在 Android 13 之前,下载的 .pem 文件通常可以直接点击安装。到了 Android 14,系统对证书安装的路径做了更严格的限制,点击下载完成的 .pem 文件可能只弹出“已保存”而不进入安装向导。你需要手动进入 Settings > Security & privacy > More security settings > Encryption & credentials > Install a certificate > CA certificate,然后选择下载的 .pem 文件。注意,Android 14 还会弹出一个系统级警告,告诉你安装第三方 CA 证书的风险,并要求你输入锁屏密码确认。


安装完成后,打开你的应用。如果 targetSdkVersion 是 33 或 34,且应用没有自定义 network_security_config.xml,你的应用大概率仍然不信任这个证书。Charles 的 SSL Proxying 日志里会继续显示握手失败。这时候,你需要在应用的 res/xml/network_security_config.xml 里添加:


<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>

并在 AndroidManifest.xml<application> 标签里声明 android:networkSecurityConfig="@xml/network_security_config"。这是 Android 官方文档里明确记录的调试手段,也是 Charles 在现代 Android 上能抓到包的最关键一步。不要试图去修改设备的 /system/etc/security/cacerts/ 目录来做全局系统证书,除非你的测试机已经 root 且不怕搞坏系统信任链,否则这条路费时费力且不可复现。


Charles 还有一个长期存在的坑:证书缓存。Charles 的根证书有有效期,旧版本 Charles 生成的证书可能只有一年有效期。如果你之前在一台手机上装过旧证书,后来 Charles 升级后重新生成了根证书,但手机上的旧证书没有清理,Android 可能会因为证书冲突或缓存导致握手异常。解决方法是 Help > SSL Proxying > Reset Charles Root Certificate,然后在手机上把所有旧的 Charles 证书从用户凭据里删掉,重新安装新的。


Proxyman 的架构差异与移动端适配


Proxyman 是近几年崛起的 macOS 原生抓包工具,官网 https://proxyman.io/,采用免费增值模式,基础抓包免费,高级功能如自动重写、断点、脚本和远程设备导出需要购买 Pro 授权,价格在 49 到 69 美元/年的订阅区间,也有一次性买断选项。它的界面和交互明显比 Charles 现代,基于 Apple 的 Network Extension 框架和原生网络栈,响应速度和内存占用远优于 Charles 的 Java 进程。


Proxyman 的证书管理逻辑和 Charles 不同。打开 Proxyman 后,它会自动生成一个根证书并尝试安装到 macOS 系统钥匙串。对于 Android 设备,你需要通过 Certificate > Install Certificate on Android 进入向导,Proxyman 会生成一个二维码或提供本地证书下载链接。你也可以手动导出证书,格式通常是 .pem.cer。在 Android 端,证书安装后的信任问题与 Charles 完全一致:Android 7.0+ 的用户证书限制同样生效,Proxyman 的证书不会因为它的导出界面更美观而被系统特殊对待。


Proxyman 的代理默认监听在 9090 端口,而不是 Charles 的 8888。手机端配置代理时注意不要填错。Proxyman 对 iOS 模拟器和 Android 模拟器有更友好的自动配置支持,特别是 iOS Simulator,它可以一键安装证书到模拟器系统。但 Android 模拟器方面,由于 Android 模拟器的系统证书分区通常是只读的,且不同模拟器镜像(Google APIs vs. Google Play)对证书写入的权限不同,Proxyman 的一键安装功能在 Android 上经常需要配合 adb rootadb remount,实际体验并不比 Charles 手动推证书更顺畅。


Proxyman 真正强于 Charles 的地方在于过滤和脚本能力。它的 ScriptingMap Local 功能基于原生代码实现,延迟极低,而且支持用 JavaScript 编写拦截规则,这在 Charles 里对应的是 Map RemoteBreakpoints,但 Charles 的脚本能力相对原始,且需要额外学习它的 proprietary 配置语法。不过,如果你只是做 HTTPS 解密和基础抓包,Proxyman 的免费版已经够用。


Proxyman 有一个 Charles 很少出现的坑:网络冲突。因为 Proxyman 深度依赖 macOS 的 Network Extension,如果你的机器上同时运行着 VPN 软件(如 Shadowsocks、Clash、WireGuard 或公司内网 VPN),Proxyman 可能会和它们抢占网络扩展槽位,导致手机代理虽然连接成功,但没有任何流量进入 Proxyman 的 Flow 列表。这种冲突没有明确的错误日志,只是表现为“连上了,但抓不到包”。Charles 因为走的是传统 HTTP 代理 Socket 监听,和 VPN 软件的冲突反而少一些,虽然它也要改系统代理设置,但退出的清理机制更粗暴,通常不会残留路由规则。


Android 14 的额外限制与证书格式


Android 14 对第三方 CA 证书的安装做了进一步收紧。在旧版本 Android 上,通过浏览器下载 .pem 文件后点击通知栏的下载项可以直接进入证书安装界面。Android 14 要求用户必须进入系统设置的安全面板手动安装,而且不再允许应用隐式地调用证书安装 intent。这对 Charles 和 Proxyman 的教程都提出了新要求:你不能只告诉用户“下载证书并点击安装”,而必须明确说明进入 Settings > Security & privacy > Encryption & credentials 的路径。


另外,Charles 导出的 .pem 文件在 Android 14 上如果直接安装失败,可以尝试把后缀改为 .crt,因为某些 Android 皮肤(尤其是 Samsung One UI 和小米 HyperOS)对 MIME 类型的判断不够宽松,.pem 被识别为普通文本而不是证书。Proxyman 导出的证书格式更规范,但在某些国产 ROM 上也存在同样的后缀识别问题。


HTTPS 解密的硬边界:SSL Pinning 与双向认证


即使你完整配置了 Charles 或 Proxyman 的证书,并且用 network_security_config.xml 把用户证书加入信任链,仍然有大量流量无法解密。最常见的原因是 SSL Pinning(证书绑定)。很多应用在生产环境使用 OkHttp 的 CertificatePinner 或者 TrustManager 的自定义实现,直接比对服务器证书或公钥的哈希,而不是依赖系统信任链。这种情况下,Charles 和 Proxyman 的自签证书虽然被系统信任,但应用代码层面的校验会拒绝握手,你看到的错误通常是 SSLPeerUnverifiedExceptionCertificate pinning failure


Charles 和 Proxyman 本身都不提供绕过 SSL Pinning 的内置功能。要解决这个问题,通常需要借助 Frida、Objection 或 Xposed 框架在运行时 hook 应用的 X509TrustManager 实现。这已经不是抓包工具的配置范畴,而是逆向工程领域。很多开发者误以为 Charles 装了证书就应该万能,这是不对的。Charles 和 Proxyman 能解密的是“信任系统 CA 链”的 HTTPS 流量,对于做了证书绑定的应用,它们无能为力。


另一个极端情况是双向认证(mTLS)。如果服务器要求客户端提供证书,Charles 作为中间人无法提供原应用私钥签名的客户端证书,连接会在服务器侧被拒绝。这种情况在企业内网应用或某些金融 SDK 中比较常见,遇到时直接放弃抓包,改用应用层日志输出更为现实。


性能、稳定性与日常使用的权衡


在日常开发中,Charles 的稳定性经受住了多年考验,但它的 Java 进程内存占用偏高,长时间运行后可能出现 UI 卡顿,特别是在处理高并发视频流或大量 WebSocket 消息时。Charles 的 WebSocket 支持是完整的,但界面刷新效率不高。Proxyman 在处理现代 HTTP/2 和 WebSocket 流量时明显更流畅,而且它的请求体预览支持 JSON Tree、Protobuf 解码和 GraphQL 语法高亮,这些对移动开发调试非常实用。


价格方面,Charles 的 50 美元买断制对长期开发者很友好,一次购买,跨平台可用(Windows、macOS、Linux)。Proxyman 的免费版已经覆盖大部分基础需求,但如果你想使用自动重写规则、导出 Swagger 文档、或多人团队协作同步配置,就得进入订阅循环。我个人觉得,如果你的主要工作机在 macOS,且只抓包不解密高强度二进制协议,Proxyman 的免费版配合手动证书安装已经足够。如果你需要频繁在 Windows 和 macOS 之间切换,或者需要用到 Charles 的 Throttle Settings(弱网模拟)和 Reverse Proxies,Charles 的许可证更划算。


当工具失效时的替代思路


Charles 和 Proxyman 并非唯一选择。在服务器或 CI 环境里,没有 GUI 可供点击,这时通常用 mitmproxy 或 tcpdump 配合 SSLKEYLOGFILE。对于 Android 开发,如果只是想看自家应用的 HTTPS 请求,从 Android Studio 的 Network Inspector(旧版叫 Network Profiler)可以直接查看明文流量,完全不需要安装根证书。它的原理是 Android Profiler 通过 JVMTI 在应用进程内部插桩,不依赖系统级证书信任,因此不受 Android 7.0 用户证书限制的约束。缺点是它只能调试 debug 签名且开启 profiling 的应用,对第三方应用或 release 包无效。


另一个值得关注的工具是 adb 的内置功能。Android 11 以上的系统支持 adb shell cmd activity memory-use 等命令,但抓包方面仍然需要 proxy。Android 10 引入的 pac_proxyglobal_http_proxy 开发者选项也可以配合 Charles 做全局代理,但本质上还是绕回证书问题。


真实场景中的配置顺序


如果你现在有一台 Pixel 8 或小米 14,要抓一个 targetSdkVersion 34 的 Android 应用的 HTTPS 包,我建议按以下顺序操作,不再重复那些过时的 Android 6.0 教程。


先在桌面端启动 Charles 或 Proxyman。以 Charles 为例,确认 Proxy > macOS Proxy 已开启,记录下 Help > Local IP Address 里的局域网 IP。打开 SSL Proxying Settings,确保 Enable SSL Proxying 开启,并且 Include 里至少有一条 __PLACEHOLDER_ITALIC_0__。在手机 Wi-Fi 设置里配置手动代理,填入 IP 和 8888 端口。用浏览器访问 chls.pro/ssl,下载证书。进入 Android 设置的安全面板,找到 Install a certificate > CA certificate,选择下载的文件,输入锁屏密码完成安装。


接着,确保你的应用是 debug 包,在 res/xml/network_security_config.xml 里加入信任用户证书的声明,manifest 中指向该配置。重新编译安装应用。打开应用触发网络请求。如果 Charles 的 StructureSequence 视图里出现了明文 URL 和 JSON 响应体,说明配置成功。如果依然显示 unknown,检查 Charles 的 SSL Proxying 日志,看具体是握手失败还是证书校验失败。


使用 Proxyman 时,逻辑完全一致,只是代理端口改为 9090,证书下载路径在 Certificate > Install Certificate on Android 中。Proxyman 的界面会提示你当前证书的有效期和 SHA-256 指纹,可以在 Android 的 Trusted credentials > User 中核对,确保安装的是同一张证书。


证书装完、代理配好,如果还是抓不到包,大概率是应用做了 SSL Pinning,或者你的 targetSdkVersion 已经触发了最新 Android 版本的证书限制。回到代码里加 network_security_config 是最省时的办法,而不是在代理工具里反复折腾。

Android 14 的截屏检测 API,能做什么不能做什么 2026-07-17
VS Code 写 Android,插件生态够用吗 2026-07-17

评论区