App安全二三事

首先插播一条自己的广告——有些朋友可能都知道了,我最近创建了一个知识星球,在这里试了一周,发现私密圈子的效率果然比群要好很多,付费门槛过滤掉了大部分广告和没有意愿学习分享的人,希望在这里能聚集更多的热爱学习热爱分享的朋友,长按下面的二维码来加入《程序员修仙指南》

《App安全二三事》

App安全二三事

客户端防作弊,是一个很重要,但又很难做好的事情,矛与盾永远是道高一尺,魔高一丈。

为什么要安全

现在几乎所有App都是网络强相关的,客户端展示的很多东西都是通过接口从服务器上获取的,当然,服务器也会接收大量从客户端上传的数据,这两端在进行双向通信的时候,就很容易被第三方截获,导致数据被盗取、接口被盗刷。

App的移动安全主要包括下面几种:

  1. 密钥破解,导致本地加密数据被盗取
  2. 通信密钥破解,导致接口数据被盗取
  3. 伪造接口数据上报
  4. 接口签名被破解,导致接口可以被重放攻击

那么归结起来,实际上就是这样几种模式:

  1. 代码反编译
  2. so破解
  3. 中间人攻击

用户要的安全

对于用户来说,他所需要的安全,是自己的敏感数据不被泄漏,不被第三方所知晓,所以,客户端数据的安全,一般会使用加密的方式来保证安全,但数据既然存在本地,那么自然既需要加密,也需要解密(如果不需要解密,那么也就没有保留的必要了),所以,本地就一定会有加解密的密钥,那么为了保证这个密钥的安全,本地代码又需要进行加密,这样突然好像就进入了一个死循环,成了一个鸡生蛋,蛋生鸡的问题,这也是为什么『本地没有绝对的安全』这样一说的原因。

本地加密

本地的加密,我们通常从混淆——proguard入手,这是最简单的加密,成本最低,而且可以比较有效的扼杀一些在破解边缘徘徊的初级破解者,让他们能够悬崖勒马,浪子回头,然而,对于真正想要破解的人来说,混淆只等于加大了一点阅读难度而已,相信做开发的同学基本上也都反编译过别人家的App,通过像jadx、apktool、dex2jar这样的反编译工具,可以非常方便的找到破解的蛛丝马迹,特别像jadx这样的反编译神器,直接导出gradle工程去AS里面查看代码,简直不要太舒服。

再高级一点,我们通过Dexguard、各种第三方so加固服务、加壳服务等方式来进行保护,这些方式的确会极大的增加破解者的破解成本,到对于主流的加固技术,相应的破解技术也是非常成熟的,所以说,虽然技术很牛逼,但只要破解者知道了你加固的方式,就可以轻而易举的找到破解的方法,也就是比proguard多了一次Google的过程。

说完了这些代码的安全,我们再来看看密钥的安全问题,前面说了,密钥一定会『藏』在本地。

最低级的,密钥被直接放在Java代码中,这种基本上就是为了糊弄老板的,稍微高级点的,也放在Java代码中,但是并不是直接让你找到的,为了增加自己的一点信心,他会把密钥拆成几个部分,然后通过一定算法计算合成完整的密钥,自欺欺人罢了,再高级一点,会把密钥和加解密放so中,再进一步,同样将密钥打散,通过一定算法进行组装,再高级一点,so再做下签名校验,加个花指令,甚至是一些人肉混淆(1、I、l),一步步的,过滤了一批批小白、初级、中级、高级破解者,然而,天下无利不往,如果你的App真的有这样的价值,那也一定会吸引那些骨灰破解者,毕竟人怕出名猪怕壮。

当然Google也总是后知后觉,在各种厂商提供了TrustZone/TEE硬件加密方案后,Google也推出了Keystore,当然,最低要API26才能使用,所以在现在来说,几乎不会有App能做到最低版本26,也就没办法借助Keystore来进行安全存储了。

接口签名

接口上的安全,最基本的保证就是Https,同时对SSL协议的域名进行校验(关键词:X509TrustManager、hostnameVerifier),相信大部分的开发者都没有对这两个地方进行校验,在此之上,请求的接口上,我们一般会带上一个签名,或者叫token,这个加密的密钥串,就是我们身份的象征,一般来说,这个签名也就是通过前面我们千辛万苦要藏好的本地密钥来进行生成的,通常也就是那几个参数,例如时间戳、UserID、IMEI、Mac地址等等进行拼装,然后通过DES、3DES、AES、hmacSHA1等方式进行加密后,再经过Base64进行编码生成的,这些加密过程就不赘述了,反正大家的都不一样,根据关键词大家去Google下就好了。

服务端要的安全

服务端需要的安全,主要是希望收到的请求,都真实的来自正常用户的正常触发。

但客户端在由不受信第三方(比如用户)控制的情况下,基本不存在能够验证请求是来自“自己的”客户端的方法,只能通过以下两种方式来增加破解者的破解成本。

  • 本地秘钥+算法,用于生成接口签名,难点在于如何保证本地秘钥和算法的安全性,也就是我们前面说的
  • 动态秘钥,将密钥的生成放在服务端,难点在于如何保证通信协议的安全性,同时也需要本地密钥来保证请求动态密钥的接口安全

动态秘钥下发的方案,需要在保证通信协议安全的情况下,才有实现价值,例如某活动页面的刷榜,可以增加一个前置依赖接口用于动态返回秘钥,客户端使用该动态秘钥来进行活动页面的请求,秘钥不存本地,每次请求都是新的秘钥,设置网络请求框架的NO_PROXY模式,就是一个最简单的方案。

考虑到服务器设备的安全性,目前主流的防作弊检测都是在服务端进行,当然最主要的原因还是本地根本没办法保证绝对的安全。

识别用户请求链路

根据必要的API调用流程和闭环,限制一组API调用中不同个体API相对于其它API的调用频率(相对次数)限制。设定几个隐秘的参数关联逻辑,是跟业务逻辑环环相扣的,如果其他人想要自己拼装参数,往往会打破这个隐秘约束。

但这个检测通常需要耗费一定的系统资源,同时,当业务比较复杂的时候,如何保证请求检测的实时性和高效性,就成了一个很难平衡的问题。

网关层拦截、人机识别

  • 网关层拦截同IP的大量重复请求,设置同IP访问的阈值。
  • 大数据识别,对识别为恶意请求的进行封号处理

这是目前比较主流的做法。

TCP加密

目前大部分的App都是通过Http来进行数据交互,但基于TCP,我们可以实现自己的通信协议,另外,利用TCP包的无序性来增加破解的难度,这样,利用TCP心跳来维持一个安全的通信通道,也是一个非常不错的方案,不过操作难度比较大。

修改业务逻辑处理方式

在设计业务技术实现方案时,将业务判断逻辑放在后端,客户端只做指令上发,判断是否生效,在服务端进行判断。

后现代安全

量子加密、白盒加密、人工智能分析,这些基本都是下一代的安全策略,就当前来说,还比较虚幻,不过只要技术一旦成熟,一定将是划时代的里程碑。

另外,知识星球是可以通过分享来获取奖励的,在『程序员修仙智能』中,点击左上角可以进行分享界面,选择分享星球即可拿到自己的奖励。

《App安全二三事》

    原文作者:算法小白
    原文地址: https://juejin.im/post/5b138338f265da6e1804bd12
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞