写点什么

移动端防抓包实践

作者:杨充
  • 2022-12-10
    北京
  • 本文字数:11030 字

    阅读完需:约 36 分钟

目录介绍

  • 01.整体概述介绍

  • 1.1 项目背景

  • 1.2 思考问题

  • 1.3 设计目标

  • 1.4 收益分析

  • 02.市面抓包的分析

  • 2.1 Https 三要素

  • 2.2 抓包核心原理

  • 2.3 搞定 CA 证书

  • 2.4 突破 CA 证书校验

  • 2.5 如何搞定加解密

  • 2.6 Charles 原理

  • 2.7 抓包原理图

  • 2.8 抓包核心流程

  • 03.防止抓包思路

  • 3.1 先看如何抓包

  • 3.2 设置配置文件

  • 3.3 数据加密处理

  • 3.4 避免黑科技抓包

  • 04.防抓包实践开发

  • 4.1 App 安全配置

  • 4.2 关闭代理

  • 4.3 证书校验

  • 4.4 双向认证

  • 4.5 防止挂载抓包

  • 4.6 数据加解密

  • 4.7 证书锁定

  • 4.8 Sign 签名

  • 4.9 其他的方式

  • 05.架构设计说明

  • 5.1 整体架构设计

  • 5.2 关键流程图

  • 5.3 稳定性设计

  • 5.4 降级设计

  • 5.5 异常设计说明

  • 06.防抓包功能自测

  • 6.1 网络请求测试

  • 6.2 抓包测试

  • 6.3 黑科技挂载测试

  • 6.4 逆向破解测试

01.整体概述介绍

1.1 项目背景

  • 通讯安全是 App 安全检测过程中非常重要的一项

  • 针对该项的主要检测手段就是使用中间人代理机制对网络传输数据进行抓包、拦截和篡改,以检验 App 在核心链路上是否有安全漏洞。

  • 保证数据安全

  • 通过 charles 等工具可以对 app 的网络请求进行抓包,这样这些信息就会被清除的提取出来,会被不法分子进行利用。

  • 不想被竞争对手逆向抓包

  • 不想自身 App 的数据被别人轻而易举地抓包获取到,从而进行类似业务或数据分析、爬虫或网络攻击等破坏性行为。

1.2 思考问题

  • 开发项目的时候,都需要抓包,很多情况下即使是 Https 也能正常抓包正常。那么问题来了:

  • 抓包的原理是?任何 Https 的 app 都能抓的到吗?如果不能,哪些情况下可以抓取,哪些情况下抓取不到?

  • 什么叫做中间人攻击?

  • 使用 HTTPS 协议进行通信时,客户端需要对服务器身份进行完整性校验,以确认服务器是真实合法的目标服务器。

  • 如果没有校验,客户端可能与仿冒的服务器建立通信链接,即“中间人攻击”。

1.3 设计目标

  • 防止 App 被各种方式抓包

  • 做好各种防抓包安全措施,避免各种黑科技抓包。

  • 沉淀为技术库复用

  • 目前只是针对 App 端有需要做防抓包措施,后期其他业务线可能也有这个需要。因此下沉为工具库,傻瓜式调用很有必要。

  • 该库终极设计目标如下所示

  • 第一点:必须是低入侵性,对原有代码改动少,最简单的加入是一行代码设置即可。完全解耦合。

  • 第二点:可以动态灵活配置,支持配置禁止代理,支持配置是否证书校验,支持配置域名合法性过滤,支持拦截器加解密数据。

  • 第三点:可以检测 App 是否在双开,挂载,Xposed 攻击环境

  • 第四点:可以灵活设置加解密的 key,可以灵活替换加解密方式,比如目前采用 RC4,另一个项目想用 DES,可以灵活更换。

1.4 收益分析

  • 抓包库收益

  • 提高产品 App 的数据安全,必须对数据传输做好安全保护措施和完整性校验,以防止自身数据在网络传输中裸奔,甚至是被三方恶意利用或攻击。

  • 技能的收益

  • 下沉为功能基础库,可以方便各个产品线使用,提高开发的效率。避免跟业务解耦合。傻瓜式调用,低成本接入!

02.市面抓包的分析

2.1 Https 三要素

  • 要清楚 HTTPS 抓包的原理,首先需要先说清楚 HTTPS 实现数据安全传输的工作原理,主要分为三要素和三阶段。

  • Http 传输数据目前存在的问题

  • 1.通信使用明文,内容可能被窃听;2.不验证通信方的身份,因此可能遭遇伪装;3.无法证明报文的完整性,所以有可能遭到篡改。

  • Https 三要素分别是:

  • 1.加密:通过对称加密算法实现。

  • 2.认证:通过数字签名实现。(因为私钥只有 “合法的发送方” 持有,其他人伪造的数字签名无法通过验证)

  • 3.报文完整性:通过数字签名实现。(因为数字签名中使用了消息摘要,其他人篡改的消息无法通过验证)

  • Https 三阶段分别是:

  • 1.CA 证书校验:CA 证书校验发生在 TLS 的前两次握手,客户端和服务端通过报文获得服务端 CA 证书,客户端验证 CA 证书合法性,从而确认 CA 证书中的公钥合法性(大多数场景不会做双向认证,即服务端不会认证客户端合法性,这里先不考虑)。

  • 2.密钥协商:密钥协商发生在 TLS 的后两次握手,客户端和服务端分别基于公钥和私钥进行非对称加密通信,协商获得 Master Secret 对称加密私钥(不同算法的协商过程细节略有不同)。

  • 3.数据传输:数据传输发生在 TLS 握手之后,客户端和服务端基于协商的对称密钥进行对称加密通信。

  • Https 流程图如下

2.2 抓包核心原理

  • HTTPS 抓包原理

  • Fiddler、Charles 等抓包工具,其实都是采用了中间人攻击的方案: 将客户端的网络流量代理到 MITM(中间人)主机,再通过一系列的面板或工具将网络请求结构化地呈现出来。

  • 抓包 Https 有两个突破点

  • CA 证书校验是否合法;数据传递过程中的加密和解密。如果是要抓包,则需要突破这两点的技术,无非就是 MITM(中间人)伪造证书和使用自己的加解密方式。

  • 抓包的工作流程如下

  • 中间人截获客户端向发起的 HTTPS 请求,佯装客户端,向真实的服务器发起请求;

  • 中间人截获真实服务器的返回,佯装真实服务器,向客户端发送数据;

  • 中间人获取了用来加密服务器公钥的非对称秘钥和用来加密数据的对称秘钥,处理数据加解密。

2.3 搞定 CA 证书

  • Https 抓包核心 CA 证书

  • HTTPS 抓包的原理还是挺简单的,简单来说,就是 Charles 作为“中间人代理”,拿到了服务器证书公钥和 HTTPS 连接的对称密钥。

  • 前提是客户端选择信任并安装 Charles 的 CA 证书,否则客户端就会“报警”并中止连接。这样看来,HTTPS 还是很安全的。

  • 安装 CA 证书到手机中必须洗白

  • 抓包应用内置的 CA 证书要洗白,必须安装到系统中。而 Android 系统将 CA 证书又分为两种:用户 CA 证书和系统 CA 证书(必要 Root 权限)。

  • Android 从 7.0 开始限制 CA 证书

  • 只有系统(system)证书才会被信任。用户(user)导入的 Charles 根证书是不被信任的。相当于可以理解 Android 系统增加了安全校验!

  • 如何绕过 CA 证书这种限制呢?已知有以下四种方式

  • 第一种方式:AndroidManifest 中配置 networkSecurityConfig,App 信任用户 CA 证书,让系统对用户 CA 证书的校验给予通过。

  • 第二种方式:调低 targetSdkVersion < 24,不过这种方式谷歌市场有限制,意味着抓 HTTPS 的包越来越难操作。

  • 第三种方式:挂载 App 抓包,VirtualApp 这种多开应用可以作为宿主系统来运行其它应用,利用 xposed 避开 CA 证书校验。

  • 第四种方式:Root 手机,把 CA 证书安装到系统 CA 证书目录中,那这个假 CA 证书就是真正洗白了,难度较大。

2.4 突破 CA 证书校验

  • App 版本如何让证书校验安全

  • 1.设置 targetSdkVersion 大于 24,去掉清单文件中 networkSecurityConfig 文件中的 system 和 user 配置,设置不信任用户证书。

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

  • 证书固定的一般做法是,将公钥证书(.crt 或者 .cer 等格式)内置到 App 中,然后创建 TrustManager 时将公钥证书加进去。

  • 那么如何突破 CA 证书校验

  • 第一种:JustTrustMe 破解证书固定。Xposed 和 Magisk 都有相应的模块,用来破解证书固定,实现正常抓包。破解的原理大致是,Hook 创建 SSLContext 等涉及 TrustManager 相关的方法,将固定的证书移除。

  • 第二种:基于 VirtualApp 的 Hook 机制破解证书固定。在 VirtualApp 中加入 Hook 代码,然后利用 VirtualApp 打开目标应用进行抓包。具体看:VirtualHook

2.5 如何搞定加解密

  • 目前使用对称加密和解密请求和响应数据

  • 加密和解密都是用相同密钥。只有一把密钥,如果密钥暴露,内容就会暴露。但是这一块逆向破解有些难度。而破解解密方式就是用密钥逆向解密,或者中间人冒充使用自己的加解密方式!

  • 加密后数据镇兼顾了安全性吗

  • 不一定安全。中间人伪造自己的公钥和私钥,然后拦截信息,进行篡改。

2.6 Charles 原理

  • Charles 类似代理服务器

  • Charles 通过将软件本身设置成系统的网络访问代理服务器,使得所有的网络请求都会走一遍 Charles 代理,从而 Charles 可以截取经过它的请求,然后我们就可以对其进行网络包的分析。

  • 截取设备网络封包数据

  • Charles 对应设置:将代理功能打开,并设置一个固定的端口。默认情况下,端口号为:8888 。

  • 移动设备设置:在手机上设置 WIFI 的 HTTP 代理。注意这里的前提是,Phone 和 Charles 代理设备链接的是同一网络(同一个 ip 地址和端口号)。

  • 截取 Https 的网络封包

  • 正常情况下,Charles 是不能截取 Https 的网络包的,这涉及到 Https 的证书问题。

2.7 抓包原理图

  • Charles 抓包原理图

  • Android 上的网络抓包原来是这样工作的

  • Charles抓包

2.8 抓包核心流程

  • 抓包核心流程关键节点

  • 第一步,客户端向服务器发起 HTTPS 请求,charles 截获客户端发送给服务器的 HTTPS 请求,charles 伪装成客户端向服务器发送请求进行握手 。

  • 第二步,服务器发回相应,charles 获取到服务器的 CA 证书,用根证书(这里的根证书是 CA 认证中心给自己颁发的证书)公钥进行解密,验证服务器数据签名,获取到服务器 CA 证书公钥。然后 charles 伪造自己的 CA 证书(这里的 CA 证书,也是根证书,只不过是 charles 伪造的根证书),冒充服务器证书传递给客户端浏览器。

  • 第三步,与普通过程中客户端的操作相同,客户端根据返回的数据进行证书校验、生成密码 Pre_master、用 charles 伪造的证书公钥加密,并生成 HTTPS 通信用的对称密钥 enc_key。

  • 第四步,客户端将重要信息传递给服务器,又被 charles 截获。charles 将截获的密文用自己伪造证书的私钥解开,获得并计算得到 HTTPS 通信用的对称密钥 enc_key。charles 将对称密钥用服务器证书公钥加密传递给服务器。

  • 第五步,与普通过程中服务器端的操作相同,服务器用私钥解开后建立信任,然后再发送加密的握手消息给客户端。

  • 第六步,charles 截获服务器发送的密文,用对称密钥解开,再用自己伪造证书的私钥加密传给客户端。

  • 第七步,客户端拿到加密信息后,用公钥解开,验证 HASH。握手过程正式完成,客户端与服务器端就这样建立了”信任“。

  • 在之后的正常加密通信过程中,charles 如何在服务器与客户端之间充当第三者呢?

  • 服务器—>客户端:charles 接收到服务器发送的密文,用对称密钥解开,获得服务器发送的明文。再次加密, 发送给客户端。

  • 客户端—>服务端:客户端用对称密钥加密,被 charles 截获后,解密获得明文。再次加密,发送给服务器端。由于 charles 一直拥有通信用对称密钥 enc_key,所以在整个 HTTPS 通信过程中信息对其透明。

03.防止抓包思路

3.1 先看如何抓包

  • 使用 Charles 需要做哪些操作

  • 1.电脑上需要安装证书。这个主要是让 Charles 充当中间人,颁布自己的 CA 证书。

  • 2.手机上需要安装证书。这个是访问 Charles 获取手机证书,然后安装即可。

  • 3.Android 项目代码设置兼容。Google 推出更加严格的安全机制,应用默认不信任用户证书(手机里自己安装证书),自己的 app 可以通过配置解决,相当于信任证书的一种操作!

  • 尤其可知抓包的突破口集中以下几点

  • 第一点:必须链接代理,且跟 Charles 要具有相同 ip。思路:客户端是否可以判断网络是否被代理了

  • 第二点:CA 证书,这一块避免使用黑科技 hook 证书校验代码,或者拥有修改 CA 证书权限。思路:集中在可以判断是否挂载

  • 第三点:冒充中间人 CA 证书,在客户端 client 和服务端 server 之间篡改拦截数据。思路:可以做 CA 证书校验

  • 第四点:为了可以在 7.0 上抓包,App 往往配置清单文件 networkSecurityConfig。思路:线上环境去掉该配置

3.2 设置配置文件

  • 一个是 CA 证书配置文件

  • debug 包为了能够抓包,需要配置 networkSecurityConfig 清单文件的 system 和 user 权限,只有这样才会信任用户证书。

  • 一个是检验证书配置

  • 不论是权威机构颁发的证书还是自签名的,打包一份到 app 内部,比如存放在 asset 里。然后用这个 KeyStore 去引导生成的 TrustManager 来提供证书验证。

  • 一个是检验域名合法性

  • Android 允许开发者重定义证书验证方法,使用 HostnameVerifier 类检查证书中的主机名与使用该证书的服务器的主机名是否一致。

  • 如果重写的 HostnameVerifier 不对服务器的主机名进行验证,即验证失败时也继续与服务器建立通信链接,存在发生“中间人攻击”的风险。

  • 如何查看 CA 证书的数据

  • 证书验证网站SSL配置检查网站

3.3 数据加密处理

  • 网络数据加密的需求

  • 为了项目数据安全性,对请求体和响应体加密,那肯定要知道请求体或响应体在哪里,然后才能加密,其实都一样不论是加密 url 里面的 query 内容还是加密 body 体里面的都一样。

  • 对数据哪里进行加密和解密

  • 目前对数据返回的 data 进行加解密。那么如何做数据加密呢?目前项目中采用 RC4 加密和解密数据。

  • 抓取到的内容为乱码

  • 有的 APP 为了防止抓取,在返回的内容上做了层加密,所以从 Charles 上看到的内容是乱码。这种情况下也只能反编译 APP,研究其加密解密算法进行解密。难度极大!

3.4 避免黑科技抓包

  • 基于 Xposed(或者)黑科技破解证书校验

  • 这种方式可以检查是否有 Xposed 环境,大概的思路是使用 ClassLoader 去加载固定包名的 xp 类,或者手动抛出异常然后捕获去判断是否包含 Xposed 环境。

  • 基于 VirtualApp 挂载 App 突破证书访问权限

  • 这个 VirtualApp 相当于是一个宿主 App(可以把它想像成桌面级 App),它突破证书校验。然后再实现挂载 App 的抓包。判断是否是双开环境!

04.防抓包实践开发

4.1 App 安全配置

  • 添加配置文件

  • android:networkSecurityConfig="@xml/network_security_config"

  • 配置 networkSecurityConfig 抓包说明

  • 中间人代理之所有能够获取到加密密钥就是因为我们手机上安装并信任了其代理证书,这类证书安装后都会被归结到用户证书一类,而不是系统证书。

  • 那我们可以选择只信任系统内置的系统证书,而屏蔽掉用户证书(Android7.0 以后就默认是只信任系统证书了),就可以防止数据被解密了。

  • 实现 App 防抓包安全配置方式有两种:

  • 一种是 Android 官方提供的网络安全配置;另一种也可以通过设置网络框架实现(以 okhttp 为例)。

  • 第一种:具体可以看清单配置文件,相当于 base-config 标签下去掉 <certificates src="user" /> 这组标签。

  • 第二种:需要给 okhttpClient 配置 X509TrustManager 来监听校验服务端证书有效性。遍历设备上信任的证书,通过证书别名将用户证书(别名中含有 user 字段)过滤掉,只将系统证书添加到验证列表中。

  • 该方案优点和缺点分析说明

  • 优点:network_security_config 配置简单,对整个 app 网络生效,无需修改代码;代码实现对通过该网络框架请求的生效,能兼容 7.0 以前系统。

  • 缺陷:network_security_config 配置方式,7.0 以前的系统配置不生效,依然可以通过代理工具进行抓包。okhttp 配置的方式只能对使用该网络框架进行数据传输的接口生效,并不能对整个 app 生效。

  • 破解:将手机进行 root,然后将代理证书放置到系统证书列表内,就可以绕过代码或配置检查了。

4.2 关闭代理

  • charles 和 fiddler 都使用代理来进行抓包,对网络客户端使用无代理模式即可防止抓包,如


    OkHttpClient.Builder()        .proxy(Proxy.NO_PROXY)        .build()
复制代码


  • no_proxy 实际上就是 type 属性为 direct 的一个 proxy 对象,这个 type 有三种

  • direct,http,socks。这样因为是直连,所以不走代理。所以 charles 等工具就抓不到包了,这样一定程度上保证了数据的安全,这种方式只是通过代理抓不到包。

  • 通常情况下上述的办法有用,但是无法防住使用 VPN 导流进行的抓包

  • 使用 VPN 抓包的原理是,先将手机请求导到 VPN,再对 VPN 的网络进行 Charles 的代理,绕过了对 App 的代理。

  • 该方案优点和缺点分析说明

  • 优点:实现简单方便,无系统版本兼容问题。

  • 缺陷:该方案比较粗暴,将一切代理都切断了,对于有合理诉求需要使用网络代理的场景无法满足。

  • 破解:使用 ProxyDroid 全局代理工具通过 iptables 对请求进行强制转发,可以有效绕过代理检测。

4.3 证书校验(单向认证)

  • 下载服务器端公钥证书

  • 为了防止上面方案可能导致的“中间人攻击”,可以下载服务器端公钥证书,然后将公钥证书编译到 Android 应用中一般在 assets 文件夹保存,由应用在交互过程中去验证证书的合法性。

  • 如何设置证书校验

  • 通过 OkHttp 的 API 方法 sslSocketFactory(sslSocketFactory,trustManager) 设置 SSL 证书校验。

  • 如何设置域名合法性校验

  • 通过 OkHttp 的 API 方法 hostnameVerifier(hostnameVerifier) 设置域名合法性校验。

  • 证书校验的原理分析

  • 按 CA 证书去验证的,若不是 CA 可信任的证书,则无法通过验证。

  • 单向认证流程图

  • 该方案优点和缺点分析说明

  • 优点:安全性比较高,单向认证校验证书在代码中是方便的,安全性相对较高。

  • 缺陷:CA 证书存在过期的问题,证书升级。

  • 破解:证书锁定破解比较复杂,比如老牌的 JustTrustMe 插件,通过 hook 各网络框架的证书校验方法,替换原有逻辑,使校验失效。

4.4 双向认证

  • 什么叫做双向认证

  • SSL/TLS 协议提供了双向认证的功能,即除了 Client 需要校验 Server 的真实性,Server 也需要校验 Client 的真实性。

  • 双向认证的原理

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

  • 用于双向认证的公钥证书和私钥代表了 Client 端身份,所以其是隐秘的,一般都是用 .p12 或者 .bks 文件 + 密钥进行存放。

  • 代码层面如何做双向认证

  • 双向校验就是自定义生成客户端证书,保存在服务端和客户端,当客户端发起请求时在服务端也校验客户端的证书合法性,如果不是可信任的客户端发送的请求,则拒绝响应。

  • 服务端根据自身使用语言和网络框架配置相应证书校验机制即可。

  • 双向认证流程图

  • 该方案优点和缺点分析说明

  • 优点:安全性非常高,使用三方工具不易破解。

  • 缺陷:服务端需要存储客户端证书,一般服务端会对应多个客户端,就需要分别存储和校验客户端证书,增加校验成本,降低响应速度。该方案比较适合对安全等级要求比较高的业务(如金融类业务)。

  • 破解:由于在服务端也做校验,在服务端安全的情况下很难被攻破。

4.5 防止挂载抓包

  • Xposed 是一个牛逼的黑科技

  • Xposed + JustTrustMe 可以破解绕过校验 CA 证书。那么这样 CA 证书的校验就形同虚设了,对 App 的危险性也很大。

  • App 多开运行在多个环境上

  • 多开 App 的原理类似,都是以新进程运行被多开的 App,并 hook 各类系统函数,使被多开的 App 认为自己是一个正常的 App 在运行。

  • 一种是从多开 App 中直接加载被多开的 App,如平行空间、VirtualApp 等,另一种是让用户新安装一个 App,但这个 App 本质上就是一个壳,用来加载被多开的 App。

  • VirtualApp 是一个牛逼的黑科技

  • 它破坏了 Android 系统本身的隔离措施,可以进行免 root hook 和其他黑科技操作,你可以用这个做很多在原来 APP 里做不到事情,于此同时 Virtual App 的安全威胁也不言而喻。

  • 如何判断是否具有 Xposed 环境

  • 第一种方式:获取当前设备所有运行的 APP,根据安装包名对应用进行检测判断是否有 Xposed 环境。

  • 第二种方式:通过自造异常来检测堆栈信息,判断异常堆栈中是否包含 Xposed 等字符串。

  • 第三种方式:通过 ClassLoader 检查是否已经加载了 XposedBridge 类和 XposedHelpers 类来检测。

  • 第四种方式:获取 DEX 加载列表,判断其中是否包含 XposedBridge.jar 等字符串。

  • 第五种方式:检测 Xposed 相关文件,通过读取/proc/self/maps 文件,查找 Xposed 相关 jar 或者 so 文件来检测。

  • 如何判断是否是双开环境

  • 第一种方式:通过检测 app 私有目录,多开后的应用路径会包含多开软件的包名。还有一种思路遍历应用列表如果出现同样的包名,则被认为双开了。

  • 第二种方式:如果同一 uid 下有两个进程对应的包名,在"/data/data"下有两个私有目录,则该应用被多开了。

  • 判断了具有 xposed 或者多开环境怎么处理 App

  • 目前使用 VirtualApp 挂载,或者 Xposed 黑科技去 hook,前期可以先用埋点统计。测试学而思 App 发现挂载在 VA 上是推出 App。

4.5 数据加解密

  • 针对数据加解密入口

  • 目前在网络请求类里添加拦截器,然后在拦截器中处理 request 请求和 response 响应数据的加密和解密操作。

  • 主要是加密什么数据

  • 在 request 请求数据阶段,如果是 get 请求加密 url 数据,如果是 post 请求则加密 url 数据和 requestBody 数据。

  • 在 response 响应数据阶段,

  • 如何进行加密:发起请求(加密)

  • 第一步:获取请求的数据。主要是获取请求 url 和 requestBody,这一块需要对数据一块处理。

  • 第二步:对请求数据进行加密。采用 RC4 加密数据

  • 第三步:根据不同的请求方式构造新的 request。使用 key 和 result 生成新的 RequestBody 发起网络请求

  • 如何进行解密:接收返回(解密)

  • 第一步:常规解析得到 result ,然后使用 RC4 工具,传入 key 去解密数据得到解密后的字符串

  • 第二步:将解密的字符串组装成 ResponseBody 数据传入到 body 对象中

  • 第三步:利用 response 对象去构造新的 response,然后最后返回给 App

4.7 证书锁定

  • 证书锁定是 Google 官方比较推荐的一种校验方式

  • 原理是在客户端中预先设置好证书信息,握手时与服务端返回的证书进行比较,以确保证书的真实性和有效性。

  • 如何实现证书锁定

  • 有两种实现方式:一种通过 network_security_config.xml 配置,另一种通过代码设置;


    //第一种方式:配置文件    <network-security-config>        <domain-config>            <domain includeSubdomains="true">api.zuoyebang.cn</domain>            <pin-set expiration="2025-01-01">                <pin digest="SHA-256">38JpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhK90=</pin>                <!-- 备用证书信息,一般为域名证书的二级证书 -->                <pin digest="SHA-256">9k1a0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM90K=</pin>            </pin-set>        </domain-config>    </network-security-config>        //第二种方式:代码设置    fun sslPinning(): OkHttpClient {        val builder = OkHttpClient.Builder()        val pinners = CertificatePinner.Builder()            .add("api.zuoyebang.cn", "sha256//89KpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRh00L=")            .add("api.zuoyebang.com", "sha256//a8za0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1o=09")            .build()        builder.apply {            certificatePinner(pinners)        }        return builder.build()    }
复制代码


  • 该方案优点和缺点分析说明

  • 优点:安全性高,配置方式也比较简单,并能实现动态更新配置。

  • 缺陷:网络安全配置无法实现证书证书的动态更新,另外该配置也受 Android 系统影响,对 7.0 以前的系统不支持。代码配置相对灵活些。

  • 破解:证书锁定破解比较复杂,比如老牌的 JustTrustMe 插件,通过 hook 各网络框架的证书校验方法,替换原有逻辑,使校验失效

4.8 Sign 签名

  • 先说一下背景和问题

  • http://api.test.com/getbanner?key1=value1&key2=value2&key3=value3

  • 这种方式简单粗暴,通过调用 getbanner 方法即可获取轮播图列表信息,但是这样的方式会存在很严重的安全性问题,没有进行任何的验证,大家都可以通过这个方法获取到数据,导致产品信息泄露。

  • 在写开放的 API 接口时是如何保证数据的安全性的?

  • 请求来源(身份)是否合法?请求参数被篡改?请求的唯一性(不可复制)?

  • 问题的解决方案设想

  • 解决方案:为了保证数据在通信时的安全性,我们可以采用参数签名的方式来进行相关验证。

  • 最终决定的解决方案

  • 调用接口之前需要验证签名和有效时间,要生成一个 sign 签名。先拼接-后转码-再加密-再发请求!

  • sign 签名校验实践

  • 需要对请求参数进行签名验证,签名方式如下:key1=value1&key2=value2&key3=value3&secret=yc 。对这个字符串进行 md5 一下。

  • 然后被 sign 后的接口就变成了:http://api.test.com/getbanner?key1=value1&key2=value2&key3=value3&sign=xxx

  • 为什么在获取 sign 的时候建议使用 secret 参数?secret 仅作加密使用,添加在参数中主要是 md5,为了保证数据安全请不要在请求参数中使用。

  • 服务端对 sign 校验

  • 这样请求的时候就需要合法正确签名 sign 才可以获取数据。这样就解决了身份验证和防止参数篡改问题,如果请求参数被人拿走,没事,他们永远也拿不到 secret,因为 secret 是不传递的。再也无法伪造合法的请求。

  • 如何保证请求的唯一性

  • http://api.test.com/getbanner?key1=value1&key2=value2&key3=value3&sign=xxx&stamp=201803261407

  • 通过 stamp 时间戳用来验证请求是否过期。这样就算被人拿走完整的请求链接也是无效的。

  • Sign 签名安全性分析:

  • 通过上面的案例,安全的关键在于参与签名的 secret,整个过程中 secret 是不参与通信的,所以只要保证 secret 不泄露,请求就不会被伪造。

05.架构设计说明

5.1 整体架构设计

  • 如下所示

5.2 关键流程图

5.3 稳定性设计

  • 对于请求和响应的数据加解密要注意

  • 在网络上交换数据(网络请求数据)时,可能会遇到不可见字符,不同的设备对字符的处理方式有一些不同。

  • Base64 对数据内容进行编码来适合传输。准确说是把一些二进制数转成普通字符用于网络传输。统统变成可见字符,这样出错的可能性就大降低了。

5.4 降级设计

  • 可以一键配置 AB 测试开关


    .setMonitorToggle(object : IMonitorToggle {        override fun isOpen(): Boolean {            //todo 是否降级,如果降级,则不使用该功能。留给AB测试开关           return false        }    })
复制代码

5.5 异常设计说明

  • base64 加密和解密导致错误问题

  • Android 有自带的 Base64 实现,flag 要选 Base64.NO_WRAP,不然末尾会有换行影响服务端解码。导致解码失败。

5.6 Api 文档

  • 关于初始化配置


    NotCaptureHelper.getInstance().config = CaptureConfig.builder()            //设置debug模式        .setDebug(true)            //设置是否禁用代理        .setProxy(false)            //设置是否进行数据加密和解密,        .setEncrypt(true)            //设置cer证书路径        .setCerPath("")            //设置是否进行CA证书校验        .setCaVerify(false)            //设置加密和解密key        .setEncryptKey(key)            //设置参数        .setReservedQueryParam(OkHttpBuilder.RESERVED_QUERY_PARAM_NAMES)        .setMonitorToggle(object : IMonitorToggle {            override fun isOpen(): Boolean {                //todo 是否降级,如果降级,则不使用该功能。留给AB测试开关               return false            }        })        .build()
复制代码


  • 设置 okHttp 配置


    NotCaptureHelper.getInstance().setOkHttp(app,okHttpBuilder)
复制代码


  • 如何设置自己的加解密方式


    NotCaptureHelper.getInstance().encryptDecryptListener = object : EncryptDecryptListener {        /**         * 外部实现自定义加密数据         */        override fun encryptData(key: String, data: String): String {            LoggerReporter.report("NotCaptureHelper", "encryptData data : $data")            val str = data.encryptWithRC4(key) ?: ""            LoggerReporter.report("NotCaptureHelper", "encryptData str : $str")            return str        }        /**         * 外部实现自定义解密数据         */        override fun decryptData(key: String, data: String): String {            LoggerReporter.report("NotCaptureHelper", "decryptData data : $data")            val str = data.decryptWithRC4(key) ?: ""            LoggerReporter.report("NotCaptureHelper", "decryptData str : $str")            return str        }    }
复制代码

5.7 防抓包功能自测

  • 网络请求测试

  • 正常请求,测试网络功能是否正常

  • 抓包测试

  • 配置 fiddler,charles 等工具

  • 手机上设置代理

  • 手机上安装证书

  • 单向认证测试:进行网络请求,会提示 SSLHandshakeException 即 ssl 握手失败的错误提示,即表示 app 端的单向认证成功。

  • 数据加解密:进行网络请求,看一下请求参数和响应 body 数据是否加密,如果看不到实际 json 实体则表示加密成功。

防抓包库:https://github.com/yangchong211/YCToolLib

综合库:https://github.com/yangchong211/YCAppTool

视频播放器:https://github.com/yangchong211/YCVideoPlayer

发布于: 刚刚阅读数: 5
用户头像

杨充

关注

还未添加个人签名 2018-07-30 加入

还未添加个人简介

评论

发布
暂无评论
移动端防抓包实践_杨充_InfoQ写作社区