Android平台HTTPS抓包解决方案及问题分析

HTTP协议发展至今已经有二十多年的历史,整个发展的趋势主要是两个方向:效率和安全。效率方面,从HTTP1.0的一次请求一个链接,到HTTP1.1的链接复用,到SPDY/HTTP2的多路复用,到QUIC/HTTP3的基于UDP传输,在效率方面愈来愈高效。安全方面,从HTTP的明文,到HTTP2强制使用TLSv1.2,到QUIC/HTTP3强制使用TLSv1.3,愈来愈注重数据传输的安全性。总而言之,HTTP协议的发展对用户是友好的,可是对开发者而言却不那么友善。php

抓包是每一个程序员的必修技能之一,尤为是在接口调试和程序逆向方面具备广阔的用途。可是,随着愈来愈多的通讯协议使用加密的HTTPS,并且系统层面也开始强制规定使用HTTPS,抓包彷佛是显得愈来愈难了。android

本篇博客,主要详解Android平台下,HTTPS抓包的常见问题以及解决办法。工欲善其事必先利其器,博客中以HttpCanary做为抓包工具进行讲解。更多HttpCanary的资料,请见:github.com/MegatronKin…git

1. 抓包原理

几乎全部网络数据的抓包都是采用中间人的方式(MITM),包括你们经常使用的Fiddler、Charles等知名抓包工具,HttpCanary一样是使用中间人的方式进行抓包。程序员

从上面这个原理图,能够看出抓包的核心问题主要是两个:github

  • MITM Server如何假装成真正的Server;
  • MITM Client如何假装成真正的Client。

第一个问题,MITM Server要成为真正的Server,必须可以给指定域名签发公钥证书,且公钥证书可以经过系统的安全校验。好比Client发送了一条https://www.baidu.com/的网络请求,MITM Server要假装成百度的Server,必须持有www.baidu.com域名的公钥证书并发给Client,同时还要有与公钥相匹配的私钥。后端

MITM Server的处理方式是从第一个SSL/TLS握手包Client Hello中提取出域名www.baidu.com,利用应用内置的CA证书建立www.baidu.com域名的公钥证书和私钥。建立的公钥证书在SSL/TLS握手的过程当中发给Client,Client收到公钥证书后会由系统会对此证书进行校验,判断是不是百度公司持有的证书,但很明显这个证书是抓包工具伪造的。为了可以让系统校验公钥证书时认为证书是真实有效的,咱们须要将抓包应用内置的CA证书手动安装到系统中,做为真正的证书发行商(CA),即洗白。这就是为何,HTTPS抓包必定要先安装CA证书。浏览器

第二个问题,MITM Client假装成Client。因为服务器并不会校验Client(绝大部分状况),因此这个问题通常不会存在。好比Server通常不会关心Client究竟是Chrome浏览器仍是IE浏览器,是Android App仍是iOS App。固然,Server也是能够校验Client的,这个后面分析。安全

2. 安装CA证书

抓包应用内置的CA证书要洗白,必须安装到系统中。而Android系统将CA证书又分为两种:用户CA证书和系统CA证书。顾明思议,用户CA证书是由用户自行安装的,系统CA证书是由系统内置的,很明显后者更加真实有效。服务器

系统CA证书存放在/etc/security/cacerts/目录下,名称是CA证书subjectDN的Md5值前四位移位取或,后缀名是.0,好比00673b5b.0。考虑到安全缘由,系统CA证书须要有Root权限才能进行添加和删除。微信

对于非Root的Android设备,用户只能安装用户CA证书。

不管是系统CA证书仍是用户CA证书,均可以在设置->系统安全->加密与凭据->信任的凭据中查看:

3. Android 7.0的用户CA证书限制

Android从7.0开始系统再也不信任用户CA证书(应用targetSdkVersion >= 24时生效,若是targetSdkVersion < 24即便系统是7.0+依然会信任)。也就是说即便安装了用户CA证书,在Android 7.0+的机器上,targetSdkVersion >= 24的应用的HTTPS包就抓不到了。

好比上面的例子,抓包工具用内置的CA证书,建立了www.baidu.com域名的公钥证书发给Client,系统校验此证书时发现是用户CA证书签发的,sorry。。。

那么,咱们若是绕过这种限制呢?已知有如下四种方式(低于7.0的系统请忽略):

3.1 AndroidManifest中配置networkSecurityConfig

若是咱们想抓本身的App,只须要在AndroidManifest中配置networkSecurityConfig便可:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config" ... >
        ...
    </application>
</manifest>
复制代码
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>
复制代码

这样即表示,App信任用户CA证书,让系统对用户CA证书的校验给予经过。更多相关信息,详见Network security configuration

3.2 调低targetSdkVersion < 24

若是想抓一个App的包,能够找个历史版本,只须要其targetSdkVersion < 24便可。然而,随着GooglePlay开始限制targetSdkVersion,如今要求其必须>=26,2019年8月1往后必须>=28,国内应用市场也开始逐步响应这种限制。绝大多数App的targetSdkVersion都将大于24了,也就意味着抓HTTPS的包愈来愈难操做了。

3.3 平行空间抓包

若是咱们但愿抓targetSdkVersion >= 24的应用的包,那又该怎么办呢?咱们可使用平行空间或者VirtualApp来曲线救国。平行空间和VirtualApp这种多开应用能够做为宿主系统来运行其它应用,若是平行空间和VirtualApp的targetSdkVersion < 24,那么问题也就解决了。

在此,我推荐使用平行空间,相比部分开源的VirtualApp,平行空间运行得更加稳定。但必须注意平行空间的版本4.0.8625如下才是targetSdkVersion < 24,别安装错了。固然,HttpCanary的设置中是能够直接安装平行空间的。

3.4 安装到系统CA证书目录

对于Root的机器,这是最完美最佳的解决方案。若是把CA证书安装到系统CA证书目录中,那这个假CA证书就是真正洗白了,不是真的也是真的了。因为系统CA证书格式都是特殊的.0格式,咱们必须将抓包工具内置的CA证书以这种格式导出,HttpCanary直接提供了这种导出选项。

操做路径:设置 -> SSL证书设置 -> 导出HttpCanary根证书 -> System Trusted(.0)

PS. 很不幸的HttpCanary v2.8.0前导出的证书名称可能不正确,建议升级到v2.8.0以上版本操做。

导出.0格式的证书后,可使用MT管理器将.0文件复制到/etc/security/cacerts/目录下,或者经过adb remount而后push也可(这里稍微提一下,别在sdcard里找这个目录)。

4. Firefox证书安装

火狐浏览器Firefox自行搞了一套CA证书管理,不管是系统CA证书仍是用户CA证书,Firefox统统都不承认。这种状况,咱们须要将CA证书经过特殊方式导入到Firefox中,不然Firefox浏览网页就没法工做了。

HttpCanary v2.8.0版本提供了Firefox证书导入选项。在设置 -> SSL证书设置 -> 添加HttpCanary根证书至Firefox 中:

点击右上角复制按钮将url复制到粘贴板,而后保持此页面不动,打开Firefox粘贴输入复制的url。

出现下载证书弹框后,必定要手动勾上:信任用来标志网站和信任用来标志电子邮件用户。而后肯定便可。

5. 公钥证书固定

证书固定(Certificate Pinning)是指Client端内置Server端真正的公钥证书。在HTTPS请求时,Server端发给客户端的公钥证书必须与Client端内置的公钥证书一致,请求才会成功。

在这种状况下,因为MITM Server建立的公钥证书和Client端内置的公钥证书不一致,MITM Server就没法假装成真正的Server了。这时,抓包就表现为App网络错误。已知的知名应用,好比饿了么,就采用了证书固定。

另外,有些服务器采用的自签证书(证书不是由真正CA发行商签发的),这种状况App请求时必须使用证书固定。

证书固定的通常作法是,将公钥证书(.crt或者.cer等格式)内置到App中,而后建立TrustManager时将公钥证书加进去。不少应用还会将内置的公钥证书假装起来或者加密,防止逆向提取,好比饿了么就假装成了png,固然对公钥证书假装或者加密没什么太大必要,纯粹自欺欺人罢了。

证书固定对抓包是个很是麻烦的阻碍,不过咱们老是有办法绕过的,就是麻烦了点。

5.1 JustTrustMe破解证书固定

Xposed和Magisk都有相应的模块,用来破解证书固定,实现正常抓包。

例如:github.com/Fuzion24/Ju…

破解的原理大体是,Hook建立SSLContext等涉及TrustManager相关的方法,将固定的证书移除。

5.2 基于VirtualApp的Hook机制破解证书固定

Xposed和Magisk须要刷机等特殊处理,可是若是不想刷机折腾,咱们还能够在VirtualApp中加入Hook代码,而后利用VirtualApp打开目标应用进行抓包。固然,有开发者已经实现了相关的功能。详见:

不过,这里CertUnpinning插件的代码有点问题,要改改。

5.3 导入真正的公钥证书和私钥

若是Client固定了公钥证书,那么MITM Server必须持有真正的公钥证书和匹配的私钥。若是开发者具备真正服务端的公钥证书和私钥,(好比百度的公钥证书和私钥百度的后端开发确定有),若是真有的话,能够将其导入HttpCanary中,也能够完成正常抓包。

在设置 -> SSL证书设置 -> 管理SSL导入证书 中,切换到服务端,而后导入公钥证书+私钥,支持.p12和.bks格式文件。

6. 双向认证

SSL/TLS协议提供了双向认证的功能,即除了Client须要校验Server的真实性,Server也须要校验Client的真实性。这种状况,通常比较少,可是仍是有部分应用是开启了双向认证的。好比匿名社交应用Soul部分接口就使用了双向认证。使用了双向认证的HTTPS请求,一样没法直接抓包。

关于双向认证的原理。

首先,双向认证须要Server支持,Client必须内置一套公钥证书 + 私钥。在SSL/TLS握手过程当中,Server端会向Client端请求证书,Client端必须将内置的公钥证书发给Server,Server验证公钥证书的真实性。

注意,这里的内置的公钥证书有区别于前面第5点的公钥证书固定,双向认证内置的公钥证书+私钥是额外的一套,不一样于证书固定内置的公钥证书。

若是一个Client既使用证书固定,又使用双向认证,那么Client端应该内置一套公钥证书 + 一套公钥证书和私钥。第一套与Server端的公钥证书相同,用于Client端系统校验与Server发来的证书是否相同,即证书固定;第二套SSL/TLS握手时公钥证书发给Server端,Server端进行签名校验,即双向认证。

用于双向认证的公钥证书和私钥表明了Client端身份,因此其是隐秘的,通常都是用.p12或者.bks文件+密钥进行存放。因为是内置在Client中,存储的密钥通常也是写死在Client代码中,有些App为了防反编译会将密钥写到so库中,好比S匿名社交App,可是只要存在于Client端中都是有办法提取出来的。

6.1 双向认证抓包

这里以S匿名社交App为例,讲解下如何抓取使用了双向认证的App的HTTPS包。

若是服务器使用了Nginx且开启了双向认证,抓包时会出现400 Bad Request的错误,以下:

有些服务器可能不会返回404,直接请求失败。

接下来看,如何使用HttpCanary配置双向认证抓包。

首先,解压APK,提取出.p12或者.bks文件,二进制的文件通常存放都在raw或者assets目录。

将client.p12文件导入手机,而后在HttpCanary的设置 -> SSL证书设置 -> 管理SSL导入证书中,切换到客户端(由于须要配给MITM Client),而后导入.p12文件。

因为双向认证的公钥证书和私钥是受密钥保护的,因此须要输入密码:

通常经过逆向能够从APK中提取出密钥,具体操做这里略过。输入密钥后,须要输入映射域名,这里使用通配符*映射全部相关域名:

导入完成后以下:

能够点进证书详情查看细节,这个client.p12文件包含公钥证书和私钥,是用于双向认证的。

配置完成后,从新进行抓包,看看效果。

能够看到,以前400 Bad Request的两个要求双向认证的请求成功了!

7. SSL重协商

有些服务器可能会开启SSL重协商,即SSL/TLS握手成功后发送请求时服务器会要求从新握手。这种状况通常比较少,可是也不排除,已知的应用好比 10000社区 就使用了SSL重协商。

因为Android系统对SSL重协商是有限支持,因此部分系统版本抓包会失败,表现为网络异常。在Android 8.1如下,SslSocket是彻底支持SSL重协商的,可是SSLEngine倒是不支持SSL重协商的,而HttpCanary解析SSL/TLS使用的是SSLEngine。在Android 8.1及以上,SSLEngine和SslSocket统一了实现,故是支持SSL重协商的。

因此,若是确认服务器使用了SSL重协商,请使用8.1及以上版本系统进行抓包。

8. 非HTTP协议抓包

若是确认了以上几点,HttpCanary仍然抓包失败,那么极有可能使用的并不是是HTTP协议。好比像微信聊天,视频直播等,使用的就不是HTTP协议,这种状况须要使用其它的抓包工具,好比Packet Capture这种直接解析TCP/UDP协议的,可是每每非HTTP协议的数据包即便抓到了也没法解析出来,由于大几率都是二进制而非文本格式的。

9. 结语

抓包是个技术活儿,须要对网络协议有大体的了解,对抓包感兴趣的同窗能够多查阅TCP、UDP、SSL/TLS、HTTP等相关资料。

HttpCanary是专业的HTTP协议抓包工具,专一HTTP协议三十年(吹过头了),不过目前还不支持QUIC/HTTP3这种新协议,等QUIC/HTTP3正式应用起来再说吧。

相关文章
相关标签/搜索