注册

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

为了提高网络数据传输的安全性,业内采用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


作者:王远道
链接:https://juejin.cn/post/7210688688921821221
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册