Android应用被抓包?防护手段需知道

2,350 阅读11分钟

为了提高网络数据传输的安全性,业内采用HTTPS的方式取代原来的HTTP,Android的应用开发也不例外,我们似乎只需要修改一下域名就能完成http到https的切换,无需做其他额外的操作,那么这个HTTPS是如何实现的?是否真的就安全了?在不同的Android版本上是否有差异?今天我们就来详细研究一下以上的问题。

Tips:本篇旨在讨论HTTPS传输的安全性,应用本地安全不在讨论范畴。

HTTPS原理

诞生背景

首先就是老生常谈的问题,什么是HTTPS,相信大家有有所了解,这里简单提一下:

由于HTTP协议(HyperText Transfer Protocol,超文本传输协议)中,传输的内容是明文的,请求一旦被劫持,内容就会完全暴露,劫持者可以对其进行窃取或篡改,因此这种数据的传输方式存在极大的安全隐患。

因此,在基于HTTP协议的基础上对传输内容进行加密的HTTPS协议(HyperText Transfer Protocol over Secure Socket Layer)便诞生了,这样即使传输的内容被劫持,由于数据是加密的,劫持者没有对应的密钥也很难对内容进行破解,从而提高的传输的安全性。

密钥协商

既然要对传输的内容进行加密,那就要约定好加密的方式与密钥管理。首先在加密方式的选择上,有对称加密非对称加密两种,这两种方式各有有缺。

对称加密:

加密和解密使用相同的密钥,这种效率比较高,但是存在密钥维护的问题。如果密钥通过请求动态下发,会有泄漏的风险。如果密钥存放到Client端,那么密钥变更时就要重新发版更新密钥,而且如果要请求多个服务器就要维护多个密钥,对于服务器端也是同理,这种密钥的维护成本极高。

非对称加密:

加密和解密使用不同的密钥,即公钥与私钥,私钥存放在Server端,不对外公开,公钥是对外公开的,这样无论是公钥打包进Client端还是由Server端动态下发,也无需担心泄漏的问题。但是这种加密方式效率较低。

HTTPS协议中,结合了对称加密和非对称加密两种方式,取其精华,弃其糟粕,发挥了两者各自的优势。

假设目前Server端有一对密钥,公钥A和私钥A,在Client端发起请求时,Server端下发公钥A给Client端,Client端生成一个会话密钥B,并使用公钥A对会话密钥B进行加密传到Server端,Server端使用私钥A进行解密得到会话密钥B,这时Client端和Server端完成了密钥协商工作,之后Client和和Server端交互的数据都使用会话密钥B进行对称加解密。在密钥协商过程中,就算被劫持,由于劫持者没有私钥A,也无法获取协商的会话密钥B,因此保证了数据传输的安全性。

密钥协商过程简图如下:

密钥协商简图.png

CA证书

上面的过程貌似解决了数据传输的安全问题,但依然有一个漏洞,就是如果劫持者篡改了Server端下发给Client端的公钥的情况。

中间人攻击(MITM攻击)简图如下:

中间人攻击简图.png

为了解决Client端对Server端下发公钥的信任问题,出现了一个被称作CA(Certificate Authority)的机构。

CA机构同样拥有采用非对称加密的公钥和私钥,公钥加上一些其他的信息(组织单位、颁发时间、过期时间等)信息被制作成一个cer/pem/crt等格式的文件,被称作证书,这些CA机构用来给其他组织单位签发证书的证书叫做根证书,根证书一般都会被预装在我们的设备中,被无条件信任

以Android设备为例,我们可以在设置 -> 安全 -> 更多安全设置 -> 加密与凭据 -> 信任的凭据中查看当前设备所有的预装的证书。

设备预装的证书.jpeg

如果Server端部署的证书是正规CA机构签发的证书(CA机构一般不会直接用根证书为企业签发域名证书,而是使用根证书生成的中间证书,一般情况下证书链是三级,根证书-中间证书-企业证书),那么我们在进行HTTPS请求的时候,不需要做其他额外操作,Client端获取到Server端下发的证书会自动与系统预装的证书进行校验,以确认证书是否被篡改。

如果Server端的证书是自签的,则需要在Client端自行处理证书校验规则,否则无法正常完成HTTPS请求。

这也是为什么,我们在Android开发网络请求时,无需做额外操作便能丝滑切换到HTTPS,但是这样真的就能保证网络请求的安全性了吗?

真的安全了吗?

经过上面的介绍我们可以了解到,如果Client端(手机、浏览器)中预装了大量正规CA机构的根证书,Server端如果是正规CA签发的证书,理论上是解决了HTTPS通信中双端的信任问题,但是还存在一个问题,就是这些Client端一般都会支持用户自行安装证书,这将会给Android端的网络安全带来哪些风险?接下来我们就继续来聊聊。

由于Android版本更新迭代较快,且不同版本之前差异较大,因此分析这个问题的时候一定要基于一个特定的系统版本,区别分析。Android 5.0(21)之前的版本太过古老,这里就不再进行分析,直接分析5.0之后的版本。

在一个只采用默认配置的的测试项目中进行HTTPS请求的抓包测试,发现在5.0(包括)到7.0(不包括)之间的版本,可以通过中间人或VPN的方式进行抓包,而7.0及以上版本则无法正常抓包,抓包情况如下

7.0以下手机代理抓包情况:

Android7.0以下.jpeg

7.0及以上手机代理抓包情况:

之所以7.0是个分水岭,是因为在Android7.0之前,系统除了对系统内置CA证书无条件信任外,对用户手动安装的CA证书也无条件信任了。

虽然说7.0及以上的设备不再信用用户自行添加的CA证书,安全性比之前的高很多,但是无门却无法阻止那些抓包的人使用7.0之下的手机,除非提高应用的最小支持版本,但这样就意味着要放弃一些用户,显然也不适用于所有情况。

那么如何在保证低版本兼容性的同时兼顾安全性呢,我们接下来继续探讨。

如何更安全

除了系统默认的安全校验之外,我们也可以通过如下手段来提高请求的安全性,让抓包变得更加困难。

禁用代理

该方式适用于所有Android版本。

在网络请求时,通过调用系统API获取当前网络是否设置了代理,如果设置了就终止请求,达到保护数据安全的目的。因为通过中间人的方式进行抓包,需要把网络请求转发到中间人的代理服务器,如果禁止了代理相当于从源头解决了问题。

优势:设置简单,系统API简单调用即可获取代理状态。

劣势:

  1. 会错杀一些因为其他场景而使用代理的用户,导致这样的用户无法正常使用

  2. 通过开启VPN在VPN上设置代理转发到中间人服务器的方式绕过

由于设置禁用代理的方式很容易被绕过且有可能影响正常开启VPN用户的使用,因此不推荐使用该方式。

数据加密

该方式适用于所有Android版本。

对请求传输的数据进行加密,然后再通过HTTPS协议传输。HTTPS本身在传输过程中会生成一个会话密钥,但是这个密钥可以被抓包获取,如果对传输的数据进行一次加密后再传输,即使被抓包也没法解析出真实的数据。

优势:安全性较高,只要密钥没有泄漏,数据被破获的风险较低

劣势:

  1. 修改同时修改Client端和Server端代码,增加加解密逻辑

  2. 加解密操作影响效率且有密钥维护的成本

在对数据安全性要求比较高的接口上,可以采用这种方式对传输内容进行增强保护。

证书单向认证

该方式适用于所有Android版本。

在默认情况下,HTTPS在握手时,Server端下证书等信息到Client端,Client端校验该证书是否为正规CA机构签发,如果是则通过校验。这里我们可以自定义校验规则,可以下载Server端的证书到打包到APK中,在请求时进行证书校验。

https单向认证.png

优势:安全性高。

劣势:证书容易过期,当前企业证书有效期只有1年,需要每年进行续签,Client需要维护证书更新的问题。

证书双向认证

该方式适用于所有Android版本。

在单向认证中,Client端会验证Server端是否安全,但是Server端并没有对Client进行校验,这里可以让Server端对Client也进行一次认证。这种认证需要在单向认证的基础上再额外创建一套证书B,存放在Client端,并在Client端完成对Server端的校验后,把Client端的公钥证书发送到Server端,由Server端进行校验,校验通过后开始密钥协商等后续步骤。

https双向认证.png

优势:安全性非常高!

劣势:

  1. Server端要存放Client端公钥证书,如果一个Server对应多个Client则需要维护多套

  2. 增加了校验成本,会降低相应速度

网络安全配置文件

该方案为google官方推荐的方案,也是一种证书的单向校验,不过在Android7.0及更高版本上,配置简单,只需要再清单文件的application节点下增加一个networkSecurityConfig项,并指向一个按固定的格式创建一个xml文件,即可完成网络安全的校验,体验相当丝滑,唯一美中不足的是该配置不支持7.0以下的版本。

在7.0及以上版本中,在xml文件夹下创建名为network_security_config_wanandroid的网络安全配置文件:

网络安全文件配置.jpeg

该文件只需要在清单文件application节点的networkSecurityConfig中引用该文件即可,如此就完成了对wanandroid.com域名及其所有次级域名的证书单向认证。

在7.0以下版本中:

由于networkSecurityConfig是7.0版本新增的,因此在所有7.0以下的设备上无法生效,所以针对7.0以下的设备只能通过代码进行认证。推荐使用OkHttp:

okHttp进行证书校验.png

需要注意的是,在通过代码配置指定域名的证书校验时,根域名和次级域名需要分别进行配置。

优势:安全性较高,代码改动少。

劣势:本质还是证书的单向认证。

选择要校验的证书

如果说采取了google推荐的方式进行安全校验,那校验证书链中的哪个证书比较合适呢?

理论上来说,当然是校验企业自己的证书最好,即证书链的第三层企业证书

image.png

但是该层证书的有效期比较短,一般每年都要进行重签,重签之后证书的Sha256就会发生变化,这时候就要及时更新Client端中信息,否则就无法正常完成校验。

为了规避证书频繁过期的问题,我们可以直接对根证书进行校验,一般来说,根证书的有效期是比较长的:

image.png

这样就不用担心证书频繁过期的问题了,但是如果再企业证书续签的时候更换了CA机构,那就必须要更新Client端中的根证书信息了,不过这就是另外的一个问题了。

只校验根证书会不会存在风险?

几乎不会,因为正规的CA机构在给一个企业颁发证书的时候,会有审核机制的,一般不会出现错误办法的状况,但在历史上确实出现过CA机构被骗,将证书颁发给了相应域名之外的人。下面截图来自Google官网:

列入黑名单.png

不过这是非常小概率的事件了,因此校验域名+根证书摘要算是即安全又避免了证书频繁过期的问题,再加上google官方的推荐,算的上是最佳解决方案了。

这篇文章就介绍到这里,感谢观看~~

上号.jpg