Charles 抓包失败案例分析
1.关闭代理!关闭代理!关闭代理!
作为一名程序员,为了顺畅的访问 GitHub 等网站,我们总会用些“辅助工具”。这些工具一般会自动开启 HTTP/HTTPS 代理从而抢占端口,导致 Charles 代理失败。
解决这个问题也很简单,Charles 抓包前,把电脑和手机的辅助工具都关掉,这样就不会有代理冲突的问题了。我们可以查看电脑的 Wi-Fi 代理界面,开启 Charles 抓包前要保证下面的选项都没被勾选就好了。
肯定也有人想过我们本地挂两个代理,报文先经过工具,然后经过 Charles 抓包,最后传输到客户端。首先这种方案是可行的,但是实际用下来会非常的卡,延迟也很高,所以并不建议这样使用。
2.确定数据走的 HTTP 协议吗?
本小节开始前我们先看一下官方是如何定义 Charles 的:
Charles is an HTTP proxy / HTTP monitor / Reverse Proxy that enables a
developer to view all of the HTTP and SSL / HTTPS traffic between
their machine and the Internet.
从介绍中我们可以看出 Charles 是一款专注于分析 HTTP 报文的网络工具,所以说对于其它协议支持是非常有限的。比如说现在的 IM 或音视频应用,出于性能和安全上的考虑,基本都是自己基于某一传输层协议自己封装的,这些数据 Charles 肯定是抓不到的。
通过阅读 Charles 的官方文档和自己的测试,Charles 支持以下协议:
- HTTP/1.1
- HTTPS
- HTTP/2
- ws(WebSocket)
- wss(WebSocket Secure,TLS 加密的 WebSocket)
- SOCKS
⚠️ 注:Charles 不支持 HTTP/3,但是大部分开启 HTTP/3 的网站都做了降级处理。例如用 Chrome 正常访问
Google 时,走的协议是 HTTP/3,连接 Charles 代理后,协议会降级到 HTTP/2
上面列出的几个协议,其实已经覆盖日常业务开发 90% 的应用场景了,若想抓取其他协议的报文,还是老老实实用 Wireshark 吧。
3.之前开了黑白名单,再次抓包忘记关了
我想日常工作中,你或你的同事肯定遇到过这种场景:
测试报上来一个 BUG,自己连上 Charles 打算分析一下 HTTP
报文想定位一下是前端问题还是后端问题,结果发现请求一直打不通,手忙脚乱半天,才发现自己开了黑白名单,请求都被 Block 掉了
上面案例的黑白名单只是一个统称,具体到 Charles 里,下面的几个配置都有可能造成误解:
- Proxy Settings 的 Options 里过滤了一些网址
- SSL Proxying Settings 没有匹配所有网址
- Block List/Allow List 做了黑白名单设置
- DNS Spoofing 做了 HOST 的映射
- Map Remote 重定向了请求
- Rewrite 重写了请求
- …
我写了几个高频的 Charles Tools,这些功能很有可能在你开启后就忘记关闭了,如果出了问题难道就要一一排查吗?
其实 Charles 有一个很不起眼的功能,那就是它的 UI 界面右下角会展示 Charles 正在开启的功能,如果你怀疑你的 Charles 哪里做了接口限制,你就扫一眼右下角开启的功能,然后依次检查就可。
4.Android 版本越高,HTTPS 报文越难抓
用户自己安装的 CA 证书没有 ROOT 权限。
我们先看一张图,这个是 Android 的证书信任页面:
从上图可以看出,Android 系统把证书信任分为两大块:
- 系统 CA 证书:基本拥有所有权限
- 用户 CA 证书:用户自行安装,权限很低
我们自己安装的 Charles 证书都属于用户 CA 证书。除了证书的权限问题,Android 的不同版本对权限的处理规则也不一样:
✅:Android 7.0 以下:信任用户 CA 证书,可以简单的理解为我们安装的证书直接获得 ROOT 权限
✅:Android 7.0 以上, targetSdkVersion < 24:信任用户 CA 证书
❌:Android 7.0 以上, targetSdkVersion >= 24:不信任用户 CA 证书
通过以上的分析,我们可以得出几个让 Android 信任 Charles 证书的方案:
- ROOT
直接 ROOT Android 手机,把 Charles 证书放到系统证书里,实现证书洗白 - 准备一个低于 Android 7.0 的手机
Android 7.0 是 2016 年的系统,按照 Android 手机两年一换代一年一更新的速度算,这种手机很难找到了 - 准备一个 targetSdkVersion < 24 的 APP 安装包
国内各大应用市场 2019 年统一要求 APP API 版本必须大于 28,这种安装包很难找到了,而且互联网产品迭代这么快,不一定能保证安装包可用 - 骚操作
正常大道走不通,Android 小道还是有很多的。社区上有各种轮子可以绕开限制,但和 Charles 关系不大,我就不展开说了。喜欢折腾的同学可以研究一下。
上面的几个方案都是针对其它 APP 的,如果你想抓包的应用是自己公司的,那就很简单了。
Android 有个 res/xml/network_security_config.xml 文件,意如其名,这个配置文件是专门控制网络安全的。
比如下面的配置,release 包只信任 system 级别的证书,debug 包同时信任 system 和 user 级别的证书,这样我们在 debug 环境下就可以开心的用 Charles 抓包了。当然安全配置肯定不止这一点内容,感兴趣的同学可以去 Android 开发者官网学习了解。
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates overridePins="true" src="system" /> </trust-anchors> </base-config> <debug-overrides> <trust-anchors> <certificates overridePins="true" src="system" /> <certificates overridePins="true" src="user" /> </trust-anchors> </debug-overrides> </network-security-config>
5.证书固定(Certificate Pinning)
证书固定(Certificate Pinning) 是指客户端内置了服务端真正的公钥证书。
在 HTTPS 请求时,服务端发给客户端的公钥证书必须和客户端内置的公钥证书一致才能请求成功。一般对安全比较重视的公司会采取这种操作。
在这种情况下,利用 Charles 抓包时,Charles 的公钥证书和客户端的公钥证书不一样,伪造的请求就会被驳回,我们就抓包失败了。那么这种情况怎么解决?
和前面介绍的一样,路其实还是有两条:
- 一条是 Hack 之路,刷机 ROOT,借助工具移除 APP 中固定的公钥证书;
- 另一条是正路,你拥有这个 APP 的开发权限,那么一般你也就拥有了公钥证书和随之配套的私钥,我们可以把证书和私钥导入到 Charles
中,解决证书固定引起的困扰。
Charles 导入公钥证书和私钥比较简单,点击 Charles -> Proxy -> SSL Proxying Setting -> Root Certificate,然后导入 .pem 或 p12 文件即可。
⚠️ 注:.p12 是一种文件格式,同时包含证书和密钥
6.证书双向验证
在绝大部分的情况下,TLS 都是客户端认证服务端的真实性的,但是在一些非常注重安全的场景下(例如匿名社交),部分 APP 会开启 TLS 的双向验证,也就是说服务端也要验证客户端的真实性。
在这种情况,客户端必然内置了一套公钥证书和私钥。相对于服务端,APP 有很大的砸壳风险,所以公钥证书和私钥一般都是极其隐蔽的,比如说写到 .so 里,隐藏在一个混淆的妈都不认识的随机数算法函数里,从而增大破译难度。
我不是安全专家对这个研究的不深,平常工作也没遇到这么刁难的问题。从功能面板看,Charles 应该也支持这种极限场景的抓包,但是个人没有具体实践过,大家可以尝试一下。
总结
Charles 抓包是一个很常见的职业技能,如果深入研究,你会发现它涉及到网络连接的五元组、报文转发的代理服务、密码学里的 MITM 和公钥证书知识。综合来看,只有掌握这些较为底层的基础知识,面对工作中各种奇奇怪怪得问题时,才能游刃有余的应对。