网络请求安全

https://httpcanary.com/zh-hans/install.html

安装根证书(必须) 安装证书要求设备必须设置锁屏密码或者图案,请按照系统提示进行设置(此乃系统限制与HttpCanary无关)

HttpCanary使用Man-in-the-Middle(MITM)技术抓取和解析TLS/SSL协议数据包,比如常见的HTTPS、WSS等加密请求,所以使用之前必须先安装HttpCanary根证书。安装时,默认点击确定即可,请勿修改配置。

SSL/TLS安全之——中间人攻击(MITM)浅析

httpcanary是通过VPN抓取数据包,因此通过禁用代理无法关闭抓包

手机上的httpcanary或PC上的ss打开都会导致正常通过代理进行抓包抓不到

https加密时,通过代理进行charles抓包时看到的数据时密文,但httpcanary看到的是明文,因为httpcanary是在应用层看到的未加密的数据和已解密的数据,加密解密发生在应用层和传输层之间。因此只能在业务上对网络参数进行加解密

Android Okhttp/Retrofit网络请求加解密实现方案

image

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

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

1. 抓包原理

几乎所有网络数据的抓包都是采用中间人的方式(MITM),包括大家常用的Fiddler、Charles等知名抓包工具,HttpCanary同样是使用中间人的方式进行抓包。

image

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

  • 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

<?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

3.3 平行空间抓包

3.4 安装到系统CA证书目录

5. 公钥证书固定

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

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

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

证书固定的一般做法是,将公钥证书(.crt或者.cer等格式)内置到App中,然后创建TrustManager时将公钥证书加进去。很多应用还会将内置的公钥证书伪装起来或者加密,防止逆向提取,比如饿了么就伪装成了png,当然对公钥证书伪装或者加密没什么太大必要,纯粹自欺欺人罢了。

证书固定对抓包是个非常麻烦的阻碍,不过我们总是有办法绕过的,就是麻烦了点。

6. 双向认证


网络数据安全

https并不能阻挡攻击者分析请求接口并发起攻击,为了增加攻击者分析请求的难度,通常可以采用两种方式:

  • 使用签名。 即给你的请求参数添加一个签名,后台服务接收到请求时,先验证签名,签名不正确的话,则不予处理。签名规则五花八门,大致策略就是根据请求参数做一些运算最后生成一个唯一的字符串当做sign,微信支付的签名大家可以做一个参考:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3

  • 数据加密。 post到服务器和从服务器返回的数据都做加密,这样的话即使攻击者拿到你的数据,他不知道你的加密算法就无能为力了。秘钥使用JNI将敏感信息写到Native层

上面说的两种方式可以同时使用,但是大家还需要考虑一个问题:如何防止攻击者获取到你的签名生成规则和加密算法,例如你加密使用的AES算法,你的秘钥放在哪里呢?