第12章 移动应用安全
12.1 概述
从 通信安全性,键盘输入安全性,客户端运行时安全性,客户端安全防护,代码安全性,客户端业务逻辑安全性。
建议采用更加安全的 app 加固解决方案,同时增加应用分发渠道监控,第一时间监控盗版,篡改应用发布上线;增加应用自身完整性校验功能,检测到应用被
篡改后,及时提醒用户卸载非法应用或者自动进行更新修复。
12.2 APP开发安全
12.2.1 AndroidManifest配置安全
每个android应用的根目录都必须有一个 AndroidManifest.xml 文件。Manifest 文件为 android 系统提供有关应用的基本信息,系统必须获得
这些信息才能运行任意应用代码。
12.2.2 Activity组件安全
Activety 组件是 android 四大组件中用户唯一能够看得见的组件,作为软件所有功能的显示与用户交互的载体,其安全性不言而喻。
12.2.3 Service组件安全
Service 组件是 android 系统中的后台进程,主要的功能是在后台进行一些耗时的操作。
12.2.4 Provider组件安全
Content Provider 组件是 android 应用的重要组件之一,管理对数据的访问,主要用于不同的应用程序之间实现数据共享。Content Provider
的数据源不止包括 SQLite 数据库,还可以是文件数据。通过将数据存储层和应用层分离,Content Provider 为各种数据源提供了一个通用的接口。
12.2.5 BroadcastReceiver组件安全
BroadcastReceiver 中文被译为广播接收者,用于处理接收到的广播,广播接收者的安全分为接收安全和发送安全两个方面。
12.2.6 WebView组件安全
WebView 是一个基于 Webkit 引擎,展现web页面的组件,app通过调用该组件就可以访问网页内容。
12.3 APP业务安全
除了在一些开发过程中遇到的安全问题外,还有一些是跟业务相关,比如反编译,二次打包,钓鱼APP等各种问题,这里涉及一些混淆,加壳,签名验证,运行时
环境检测等技术方案。除此之外,还有一些是在业务上想做更多的安全控制,比如数据防泄漏,防截屏,安全键盘等。
12.3.1 代码安全
相比iOS系统的封闭及严格的app审核及签名控制,android系统的开源以及基于java的特性,导致app在android上更容易被反编译。目前常用的一些反编译
工具(比如APKTool,dex2jar等)能够好不费劲的还原java里的明文信息,Native里的库信息也可以通过 objdump 或者 IDA 获取。而心怀不轨的人可能会通过
反编译后加入恶意的代码逻辑,重新打包一个apk文件去发布安装,也就是我们常说的 "二次打包"问题。针对这些问题,常见的解决方案是 代码混淆,加壳,反调试,
签名验证等。
1.代码混淆
app的代码混淆包括Java代码的混淆以及一些资源文件的混淆。
2.加壳
Android加壳分为 dex 加壳和对 native 加壳(即 so 文件加壳),主流的加壳技术基本可以分为四代:
1.整体dex加壳
对 classed.dex 文件进行整体加壳加密,存放在APK的资源中,运行时将加密后的classes.dex文件在内存中解密,并让Dalvik虚拟机动态
加载运行。
2.防调试防Dump
整体 dex 在内存中解密,黑客通过内存Dump的方式即可拿到明文,所以出现了防调试,防内存的Dump技术。
3.方法体抽离
相比前面整体加壳加密,第三代开始尝试只对 classes.dex 文件中的方法,函数进行抽取加密,在java虚拟机执行具体的某个方法时才将其动态
解密,并以不连续的方式存放到内存中。后面慢慢发展成将java代码内关键算法,业务逻辑等函数自动转化成 native 的C++代码进行防护。
4.VMP加壳/so加壳
我们知道程序的执行,是依靠cpu对于符合规范的指令集的解析处理。如果将原指令集通过自定义规范进行变形处理,生成新的指令集(称之为
虚拟指令集),cpu 将无法识别虚拟指令。此时若配合能够解析虚拟指令集的解析器(虚拟机),就可以达到不直接通过cpu而是通过虚拟机来执行虚拟指令。
这就是很多公司各种VMP保护方案的原理。
APP 加固的目的是提升对手攻击成本。在实际工作中,考虑到app内部复杂的业务场景和升级机制,有一些加固方案可能会存在一定的兼容性问题,用户体验要求高的
场景可能还会追求运行速度,因此需要慎重权衡。一般的思路是在app上进行各种埋点,结合后端大数据风控来降低安全风险。
3.反调试
调试器检测,一般是利用 android.Debug.isDebuggerConnected() 这个 API 来判断,还有一些其他的思路,比如调用 android 中的 flag 属性
ApplicationInfo.FLAG_DEBUGGABLE 判断是否属于 debug 模式,循环检查 android_server 调试端口和进程信息,循环检查自身 status 中的
TracePid 字段值等。
此外,还有检测模拟器,检测设备是否已经 ROOT。模拟器检测技术,一般是取一些模拟器特征,例如通过 电话管理器攻取设备 IMEI,IMSI,判断设备配置
信息与android模拟器设备配置默认值是否相同,检测设备是否有安装蓝牙设备硬件,判断当前设备 WIFI MAC 地址,检测是否具有 QEMU 虚拟机通道文件等。
ROOT 检测的思路一般是,看 root 后的手机会有哪些特质,比如,检测 su 文件是否存在以及可以执行,检测是否安装 Superuser.apk等。但实际情况
是,android 碎片化非常严重,国产手机特别喜欢修改原生 ROM,这会导致一些检测方法失效。
4.签名安全
签名验证主要是为了防止二次打包,android 签名验证一般有三种方法:
1.Java层验证,即在java代码中实现公钥信息的对比,比对的样本可以放在本地或者服务器侧。但是java代码容易被反编译,这个校验逻辑可能被篡改。
2.NDK层验证,即在 Native 代码实现公钥信息比对,对比的样本进行加密存储。我们知道 so 通过反汇编生成 ARM 代码,相对 smali 被篡改的难度
更大,再结合 so 文件加固,可以进一步增强反编译难度。
3.服务端验证,即程序通过特定方法检测获得自身代码校验值,上送服务端进行比较,从而验证合法性。这样针对那些非法或伪造,篡改过的客户端,服务端可以
直接拒绝服务,进一步保障安全。
12.3.2 数据安全
针对APP,我们说的敏感信息主要包括两方面:一是用户敏感信息;而是APP本身的敏感信息,比如核心算法,核心业务逻辑,私钥,本地存储的证书,加密算法等。
1.数据存储安全
Android 有外部存储和内部存储之分,外部存储安全隐患比较大。
涉及用户隐私哪怕是已经加过密的也不要保存在外部存储设备上。
2.数据传输安全
一般客户端使用 https 与服务端进行通信,网站启用 SSL site wide(use HTTPS only)或 HSTS(HTTP Strict Transport Security),否则
存在 SSL Strip(HTTPS 降级为 HTTP)攻击风险。
12.3.3 其他话题
1.安全键盘输入
智能手机输入需要依靠虚拟键盘,而虚拟键盘则由具体的输入法控制。
2.防截屏
为了防止恶意软件通过秘密截屏的方式得到一些APP上显示的信息,就需要对截屏进行处理。
3.钓鱼APP
通过对加固服务提供商进行规范来防止钓鱼APP,是一个不错的思路。