macOS 上 Charles 代理 HTTPS 抓包失败问题完整解决方案

macOS 上 Charles 代理 HTTPS 抓包失败问题完整解决方案

一、问题现象

在 macOS 上使用 Charles 进行 HTTPS 抓包时,经常遇到以下情况:

  • 浏览器或终端中的 HTTPS 请求返回错误,无法正常加载页面。
  • curl 命令报错:curl: (60) SSL certificate problem: self signed certificate in certificate chain
  • Charles 中请求显示 unknown 或无法解密 HTTPS 流量。

根本原因是:Charles 作为中间人代理,会用自己的自签名根证书来动态签发目标服务器的证书。但操作系统和应用程序(如 curl)默认不信任这个自签名证书,从而导致 SSL 握手失败。

二、基础环境准备

1. 设置 Charles 代理端口

Charles 默认使用 8888 端口作为 HTTP/HTTPS 代理端口。请确认:

  • 菜单栏 Proxy -> Proxy Settings -> HTTP Proxy 端口为 8888
  • 勾选 Enable transparent HTTP proxying(可选)。

2. 配置终端代理环境变量

在终端中执行以下命令,让 curl 等命令行工具通过 Charles 代理发出请求:

bash 复制代码
export http_proxy="http://127.0.0.1:8888"
export https_proxy="http://127.0.0.1:8888"
export HTTP_PROXY="http://127.0.0.1:8888"
export HTTPS_PROXY="http://127.0.0.1:8888"

注意:大小写都设置是为了兼容不同程序对环境变量的读取习惯。可以将其写入 ~/.zshrc 并用 proxy_on 函数封装,方便开关。

3. 验证代理连通性

先测试代理是否能正常连接:

bash 复制代码
curl -vv https://www.baidu.com

如果出现 HTTP/1.1 200 Connection established 以及后续的 SSL 证书错误,说明代理通道已建立,但证书信任问题尚未解决。

三、临时解决方案(每次请求指定证书)

如果不希望修改系统证书信任设置,或者只想临时测试,可以使用 curl--cacert 参数直接指定 Charles 的根证书文件。

步骤 1:导出 Charles 根证书并转换为 PEM 格式

  1. 在 Charles 菜单栏点击 Help -> SSL Proxying -> Export Charles Root Certificate and Private Key...
  2. 在弹出的窗口中设置密码(例如 123456),选择保存位置,文件格式默认为 .p12
  3. 使用 OpenSSL 将 .p12 转换为 curl 能识别的 .pem 格式:
bash 复制代码
openssl pkcs12 -in /path/to/charles-ssl-proxying.p12 -out /path/to/charles.pem -nodes
  • -in:输入的 .p12 文件路径
  • -out:输出的 .pem 文件路径(建议放在桌面或用户目录)
  • -nodes:不加密私钥,避免 curl 需要交互输入密码

执行后会要求输入导出时设置的密码,输入后回车即可。

步骤 2:使用 --cacert 发起请求

bash 复制代码
curl -k --cacert /Users/mac/Downloads/charles.pem -vv https://www.baidu.com
  • -k--insecure:跳过对目标服务器证书的验证(因为 Charles 签发的证书与百度原始证书不同,但我们已经信任 Charles 根证书,所以可以不加 -k,仅用 --cacert 即可)。实际上,为了完整验证,推荐只使用 --cacert
bash 复制代码
curl --cacert /Users/mac/Downloads/charles.pem -vv https://www.baidu.com

此时应该能正常返回 HTML 内容,Charles 中也能看到解密的 HTTPS 请求详情。

缺点 :每次 curl 都需要手动添加 --cacert 参数,比较繁琐。

四、永久解决方案(系统级信任 Charles 根证书)

让 macOS 系统以及所有命令行工具(curlgitbrew 等)默认信任 Charles 的根证书,一劳永逸。

核心思路

  • 将 Charles 根证书导入 系统钥匙串/Library/Keychains/System.keychain)。
  • 明确设置该证书为 始终信任(SSL 信任)。

详细步骤

1. 删除旧的 Charles 证书

打开"钥匙串访问"(Keychain Access),分别在 登录系统 钥匙串中搜索 Charles,删除所有相关证书(例如 Charles Proxy CA)。这可以避免新旧证书冲突。

2. 重新安装 Charles 根证书
  • 在 Charles 菜单栏点击 Help -> SSL Proxying -> Install Charles Root Certificate
  • 此时证书会被安装到 登录 钥匙串(默认位置)。
3. 将证书移动到系统钥匙串并设置为始终信任
  • 打开"钥匙串访问",在 登录 钥匙串中找到刚才安装的 Charles Proxy CA... 证书。
  • 将证书拖拽 到左侧的 系统 钥匙串中(需要输入管理员密码)。
  • 切换到 系统 钥匙串,双击该证书打开详情窗口。
  • 展开 信任 部分,将 "使用此证书时" 下拉菜单改为 "始终信任"
  • 关闭窗口,再次输入密码确认修改。
4. 重启 Charles 和终端

完全退出 Charles(Cmd+Q),关闭所有终端窗口,重新打开。

5. 测试验证

在终端直接运行:

bash 复制代码
curl -vv https://www.baidu.com

不再需要 -k--cacert,应该能够正常返回页面内容,同时 Charles 中显示完整的 HTTPS 请求和解密后的数据。

五、常见问题与排查

Q1:永久方案设置后 curl 仍然报 SSL 错误

  • 确认证书是否在 系统 钥匙串中,而不是 登录
  • 确认信任设置中的 "SSL""使用此证书时" 确实为 "始终信任"
  • 尝试在 Charles 中执行 Help -> SSL Proxying -> Reset SSL Certificates,然后重启 Charles。
  • 重启 Mac 以清理所有缓存。

Q2:浏览器可以抓包,但终端不行

  • 检查终端环境变量 https_proxy 是否正确设置。
  • 有些终端配置文件(如 .zshrc)中可能覆盖了代理变量,可以临时用 unset https_proxy 清除后再测试。
  • 确认 Charles 的 macOS Proxy 选项已勾选(Proxy -> macOS Proxy),这会自动为系统设置代理。

Q3:Charles 中某些请求仍然显示 unknown

  • 确认 SSL Proxying 已开启且 Include 规则包含 *:443 或具体域名。
  • 可能是客户端启用了 QUIC (HTTP/3) 协议,Charles 无法代理 UDP 流量。解决方法:在 Chrome 中访问 chrome://flags/#enable-quic 将其禁用,或强制客户端使用 HTTP/1.1/2。
  • 可能是客户端使用了 SSL Pinning(证书锁定),如银行 App、部分企业软件。这种情况下 Charles 无法直接解密,需要更高级的 Hook 工具(如 Frida)。

Q4:导出 .p12 时忘记密码怎么办?

  • 无法恢复密码,只能重新在 Charles 中导出新证书,设置一个你记得住的密码。

六、总结

方案 操作复杂度 持久性 适用场景
临时方案 (--cacert) 低(需每次加参数) 临时 偶尔调试,不想修改系统设置
永久方案(系统钥匙串+信任) 中(一次配置) 永久 长期开发、频繁抓包

推荐开发者在自己的 Mac 上采用永久方案,配置一次后,所有命令行工具和应用程序都能无缝通过 Charles 抓包 HTTPS 流量,极大提升效率。

如果在实践中遇到其他问题,欢迎根据具体错误信息进一步排查。Happy debugging!

相关推荐
pengyi8710154 小时前
HTTP代理抓包实操教程,零基础监控IP请求与响应数据
网络协议·tcp/ip·http
.千余4 小时前
【Linux】Socket编程UDP
linux·运维·服务器·开发语言·网络协议·学习·udp
Rudon滨海渔村4 小时前
Mac录屏教程:只需要内录电脑声音,不需要麦克风声音
macos·免费·录屏·blackhole
小辰记事本13 小时前
从零读懂RoCEv2数据包构造:从WQE到线缆上的完整旅程
服务器·网络·网络协议·rdma
北京耐用通信14 小时前
全域适配工业场景耐达讯自动化Modbus TCP 转 PROFIBUS 网关轻松实现以太网与现场总线互通
网络·人工智能·网络协议·自动化·信息与通信
YMWM_17 小时前
UDP协议详解:从原理到Python实践
网络·网络协议·udp
pengyi87101517 小时前
共享 IP 与独享 IP 怎么选?被封后升级方案避坑
网络·网络协议·tcp/ip
半壶清水20 小时前
用P4 Tutorial、BMv2 和 Mininet‌解析网络第一集------模拟环境搭建
运维·服务器·网络·网络协议·tcp/ip
BullSmall20 小时前
Promtheus和Alertmanager 之间是通过管理平面还是业务层面IP交互
网络协议·tcp/ip·平面