做为一名 Web 开发工程师,每天都会和网络打交道。Charles 做为一款网络抓包工具,几乎成了 Web 开发的标配。前端
本文是我深度使用 Charles 后总结而成,不一样于其它介绍 Charles 的文章,这篇文章不会详细介绍 Charles 的各个功能(例如 remote 和 rewrite),而是专一于分析一个问题:什么状况下 Charles 会抓包失败?android
为了解决这个问题,我会从 Charles 的原理分析,而且结合 Android/iOS 的官方政策,一一分析 Charles 抓包中的那些失效问题。看完后若是你以为有用,必定要记得给我点赞 🌟,谢谢你,这对我真的很重要!程序员
市面上绝大多数的抓包软件,背后的原理都是中间人攻击(Man-in-the-middle attack,缩写:MITM)。算法
维基百科是这样定义 MITM 的:后端
中间人攻击在密码学和计算机安全领域中是指攻击者与通信的两端分别创建独立的联系,并交换其所收到的数据,使通信的两端认为他们正在经过一个私密的链接与对方直接对话, 但事实上整个会话都被攻击者彻底控制。
上面的定义写的很清晰,我结合 Charles 画了一个图,结合箭头方向就能看懂 HTTP Packets 的流向:浏览器
只看理论有些干,咱们能够用个实例看一下 Charles 内部的工做状况。我在电脑浏览器上访问 cdn.staticfile.org
的一个 HTTP 资源,具体的网络报文我用 Wireshark 抓了一下:缓存
结合 Wireshark 的抓包报文和 Charles 的网络分析,咱们能够看出这个 HTTP 请求的报文流向:安全
56075
发起一个请求,请求发送到本地 Charles 监听的 8888
端口(MITM Server),这个链接直接在本机进行56076
(MITM Client)发起一个新的请求,由于这个网络包要入公网,因此 IP 为 192.168.31.44
(个人电脑 IP 地址,下节会介绍); cdn.staticfile.org
(Server)的 IP 为 111.63.183.223
,由于是 HTTP 请求,因此端口号为 80
111.63.183.223:80
返回一个 HTTP 响应到 Charles 的代理客户端 192.168.31.44:56076
8888
端口发送到 127.0.0.1:56075
,到这里浏览器就收到了响应在第二步和第三步中,报文通过了 Charles,Charles 这时就能够对报文进行一些加工,例如 Remote 重定向,Rewrite,缓存报文并可视化等操做。服务器
为了文章的连续性,这里我会对 Charles 的抓包代理配置进行简单的说明。若是你对这里很熟悉能够选择跳过,不太熟悉能够把文章收藏方便后续检索查阅。网络
开始配置前咱们先回顾一下基础的网络知识,网络数据若是想从 A 传输到 B,想肯定一个链接就必须肯定 5 个关键信息:源 IP 地址
,源端口
,传输层协议
,目的 IP 地址
和目的端口
。这 5 个关键信息又叫五元组
,一个五元组就能够肯定一个链接。
若是用 Charles 抓包,咱们就要对照分析一下 Client 和 MITM Server 间代理连接的五元组:
源 IP 地址
:被抓包应用的 IP 地址,通常为设备 IP,通常不作修改源端口
:被抓包应用的端口号,通常为操做系统分配,没法修改传输层协议
:Charles 目前主要代理的是 HTTP 协议,通常为 TCP目的 IP 地址
:Charles 的 IP 地址,通常为电脑本机 IP,通常不作修改目的端口
:Charles 的代理端口,默认为 8888,能够修改⚠️ 注:上述分析中只考虑了通常状况,若是你真的想改也能够改,但这种 hack 行为不在本文考虑范围内
从上面的分析咱们能够看出,想要打通五元组,咱们主要要关注两个点:目的 IP 地址和目的端口。
咱们先分析一下目的 IP 地址。由于 Charles 安装在电脑上,因此 Charles 的 IP 就是电脑的 IP。若是你是 Mac 电脑,能够按住 option
键再用鼠标点击菜单栏的 Wi-Fi 图标,获得电脑 IP 地址。也能够访问 系统偏好设置 -> 网络 获得 IP 地址。这里个人 IP 地址是 192.168.31.44
,后面会用到。
Charles 的代理端口号能够从 Charles -> Proxy -> Proxy Setttings 进行查看和更改。端口默认是 8888
,通常不建议修改。
肯定好 Charles 的 IP 和端口号后,咱们就能够分设备配置 HTTP 代理了。
不管你使用的是 window 仍是 mac,Charles 做为一款在电脑上安装的 APP,代理本机请求时,网络数据都是在本地转发的,因此相对来讲电脑端的配置是最简单的。咱们只要根据路径 Charles -> Proxy -> macOS Proxy 依次点击开启代理就可。
由于本机代理默认是关闭的,咱们也能够在 Proxy Setttings
中点击 macOS
,勾选 Enable macOS proxy on lounch
,这样每次打开 Charles 就会默认打开代理了。
想要抓 iOS 的网络包,只须要把 iOS 的网络包转发到代理 IP 和代理端口就行。
配置前咱们要保证手机和电脑在同一个局域网里(通常手机电脑连同一个 Wi-Fi 就行),而后打开 iOS 的 设置 -> 无线局域网,进入已链接的 Wi-Fi 的设置页面,滑动到最底部选择配置代理,而后手动配置代理。
服务器要输入的就是前面获得的 Charles IP 地址,案例里是 192.168.31.44
;端口是前面的 Charles 代理端口,通常为 8888
。
Android 的代理配置其实和 iOS 差很少,可是 Android 厂家众多,操做步骤不像 iOS 那么统一,一一覆盖也没有太大的意义,因此我只作个简单的步骤演示:
HTTPS 本质上就是 HTTP 协议 + TLS 协议,从创建链接的角度看,主要是在 TCP 三次握手以后又加入了四次 TLS 握手,以下图所示,TLS 握手过程当中会校验加密用的公钥证书,因此咱们就要手动安装并信任 Charles 的证书,以达到抓取 HTTPS Packets 的目的。
TLS 的加入,增强了网络的安全性的同时,也增长了抓包的复杂度,下一节我会详细解释,这里先作个证书安装的步骤演示。
⚠️ 注:证书安装前要确保 HTTP 代理已经配置完毕
电脑端安装证书是最简单的。首先点击 Charles -> Help -> SSL Proxying -> Install Charles Root Certificate 在电脑端安装证书,而后点击刚刚安装的证书,手动信任所有权限,最后输入密码保存修改就可。
iOS 安装证书相对来讲复杂一些。首先点击 Charles -> Help -> SSL Proxying -> Install Charles Root Certificate on a Mobile Derive,这时候会跳出一个弹窗,而后咱们根据提示在手机端访问 chls.pro/ssl
,下载安装 Charles CA 证书。
安装好后还要手动开启权限。先要到 通用 -> 描述文件与设备管理 -> 信任 里安装刚刚下载的证书,而后到 通用 -> 关于本机 -> 证书信任设置 -> 针对根证书启用彻底信任 里手动信任证书,这两个赞成后 iOS 就安装证书成功了。
Android 安装证书的步骤不但麻烦,做用还不大。
首先点击 Charles -> Help -> SSL Proxying -> Save Charles Root Certificate,把证书文件以 *.cer
格式保存。
⚠️ 注:Charles 保存证书文件时,有两种格式可选:.pem
和.cer
。前者是一种证书容器格式,通常是对证书进行 base64 编码;后者通常是二进制格式的证书,Android 系统对二进制格式的证书兼容性更好一些,因此咱们选择.cer
文件。
保存好文件后,咱们再用 USB 或着其它方式把 CA 证书导入到 Android 内,最后点击证书安装就可。
本节实际上是本文的重点,从 6 个方向分析 Charles 抓包失败的缘由,从代理服务器到 TLS 证书,覆盖了计算机网络的各个知识点,很是值得收藏学习。
做为一名程序员,为了顺畅的访问 GitHub 等网站,咱们总会用些“辅助工具”。这些工具通常会自动开启 HTTP/HTTPS 代理从而抢占端口,致使 Charles 代理失败。
解决这个问题也很简单,Charles 抓包前,把电脑和手机的辅助工具都关掉,这样就不会有代理冲突的问题了。咱们能够查看电脑的 Wi-Fi 代理界面,开启 Charles 抓包前要保证下面的选项都没被勾选就行了。
确定也有人想过咱们本地挂两个代理,报文先通过工具,而后通过 Charles 抓包,最后传输到客户端。首先这种方案是可行的,可是实际用下来会很是的卡,延迟也很高,因此并不建议这样使用。
本小节开始前咱们先看一下官方是如何定义 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 支持如下协议:
⚠️ 注: Charles 不支持 HTTP/3,可是大部分开启 HTTP/3 的网站都作了降级处理。例如用 Chrome 正常访问 Google 时,走的协议是 HTTP/3,链接 Charles 代理后,协议会降级到 HTTP/2
上面列出的几个协议,其实已经覆盖平常业务开发 90% 的应用场景了,若想抓取其余协议的报文,仍是老老实实用 Wireshark 吧。
我想平常工做中,你或你的同事确定遇到过这种场景:
测试报上来一个 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 哪里作了接口限制,你就扫一眼右下角开启的功能,而后依次检查就可。
在「Android 安装证书」那个小节里,我说这个步骤意义不大,根本缘由在于:用户本身安装的 CA 证书没有 ROOT 权限。
咱们先看一张图,这个是 Android 的证书信任页面:
从上图能够看出,Android 系统把证书信任分为两大块:
咱们本身安装的 Charles 证书都属于用户 CA 证书。除了证书的权限问题,Android 的不一样版本对权限的处理规则也不同:
✅:Android 7.0 如下:信任用户 CA 证书,能够简单的理解为咱们安装的证书直接得到 ROOT 权限
✅:Android 7.0 以上, targetSdkVersion < 24:信任用户 CA 证书
❌:Android 7.0 以上, targetSdkVersion >= 24:不信任用户 CA 证书
经过以上的分析,咱们能够得出几个让 Android 信任 Charles 证书的方案:
1.ROOT
直接 ROOT Android 手机,把 Charles 证书放到系统证书里,实现证书洗白
2.准备一个低于 Android 7.0 的手机
Android 7.0 是 2016 年的系统,按照 Android 手机两年一换代一年一更新的速度算,这种手机很难找到了
3.准备一个 targetSdkVersion < 24 的 APP 安装包
国内各大应用市场 2019 年统一要求 APP API 版本必须大于 28,这种安装包很难找到了,并且互联网产品迭代这么快,不必定能保证安装包可用
4.骚操做
正常大道走不通,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>
证书固定(Certificate Pinning) 是指客户端内置了服务端真正的公钥证书。
在 HTTPS 请求时,服务端发给客户端的公钥证书必须和客户端内置的公钥证书一致才能请求成功。通常对安全比较重视的公司会采起这种操做。
在这种状况下,利用 Charles 抓包时,Charles 的公钥证书和客户端的公钥证书不同,伪造的请求就会被驳回,咱们就抓包失败了。那么这种状况怎么解决?
和前面介绍的同样,路其实仍是有两条:
Charles 导入公钥证书和私钥比较简单,点击 Charles -> Proxy -> SSL Proxying Setting -> Root Certificate,而后导入 .pem
或 p12
文件便可。
⚠️ 注:
.p12
是一种文件格式,同时包含证书和密钥
在绝大部分的状况下,TLS 都是客户端认证服务端的真实性的,可是在一些很是注重安全的场景下(例如匿名社交),部分 APP 会开启 TLS 的双向验证,也就是说服务端也要验证客户端的真实性。
在这种状况,客户端必然内置了一套公钥证书和私钥。相对于服务端,APP 有很大的砸壳风险,因此公钥证书和私钥通常都是极其隐蔽的,好比说写到 .so
里,隐藏在一个混淆的妈都不认识的随机数算法函数里,从而增大破译难度。
我不是安全专家对这个研究的不深,日常工做也没遇到这么刁难的问题。从功能面板看,Charles 应该也支持这种极限场景的抓包,可是我的没有具体实践过,你们能够尝试一下。
Charles 抓包是一个很常见的职业技能,若是深刻研究,你会发现它涉及到网络链接的五元组、报文转发的代理服务、密码学里的 MITM 和公钥证书知识。综合来看,只有掌握这些较为底层的基础知识,面对工做中各类奇奇怪怪得问题时,才能游刃有余的应对。
若是你们以为这篇文章不错,请必定不要忘记点赞 🌟 支持做者,谢谢你,这对我真的很重要!
欢迎你们关注公众号「卤蛋实验室」,写一些不注水的原创干货。
欢迎关注个人我的网站:supercodepower.com,由于各大平台修改文章都会从新审核,我的博客修改更新更方便一些。
本人以前写过一些计算机网络相关的博文,横跨多个坑点,欢迎你们围观点赞: