Android 开发者经常会遇到需要在客户端对一些敏感信息进行保存的情况,例如我们使用开源库SQLCipher对数据库进行加密,我们使用Facebook 的Conceal对磁盘上大文件的加密,无论哪种情况,都会涉及加密所用的密钥如何在客户端安全存放的问题,另外,现在的APP一般都会集成很多第三方的SDK,用于诸如支付,同hi,推送等功能,这时一般都需要向这些第三方APK官方网站申请API key,我们当然不希望这些密钥或者 API key能被第三方通过反编译很轻易的获取,因此,如何在客户端保存敏感信息,是关系到整个APP是否安全的关键问题。
常见的敏感信息隐藏策略主要有:
1 敏感信息嵌套在string.xml中
2 敏感信息隐藏在Java源代码中
3 敏感信息隐藏在BuildConfig中
4 使用DexGuard
5 对敏感信息进行伪装或者加密
6 敏感信息隐藏在原生函数库中(.so文件)
7 对APK进行加固处理
敏感信息嵌套在string.xml中
由于密钥或者API key一般都是以字符串的形式存在的,最常见的一种保存方法是将其存放在工程的res/values/string.xml文件中

这种方法的安全性是极低的,第三方只需要使用ApkTool等工具对APK的资源文件进行反编译,就能轻易的拿到这个string.xml文件,里面的内容是一目了然的
敏感信息隐藏在Java源代码中
将密钥或者API key以字符串或者字符数组的形式硬编码到代码中,这也是普通开发者常用的一种方式。

同样的,这种方式的安全性也是极低的,通过使用dex2jar等工具对classes.dex文件进行反编译,可以得到classes-dex2jar.jar包,这时使用JD-GUI可以查看反编译后的源码:

敏感信息隐藏在BuildConfig中
Android Gradle Plugin为我们提高了BuildConfig文件,我们可以把敏感信息存放在这里,同时通过将敏感信息存放工程的gradle.properties,可以避免将其上传到版本控制系统上,从而将敏感信息控制在少数人手里,而不是暴漏给所有具有svn或者git权限的人。
要将信息保存到BuildConfig文件中,需要在app/build.gradle文件中设置如下

其中buildConfigField函数用于给BuildConfig文件添加一个字段,原型如下:


而“\”${staticAppLey}\""的取值定义在工程的gradle.properties文件中

这种方式安全级别也是极低的,我们对生成的APK进行反编译后,查看BuildConfig.class文件,可以直接看到APIkey 的取值

使用DexGuard
我们知道,Android已经默认集成了ProGuard,它是一个免费的用于压缩,优化和混淆Java字节码的工具,混淆的功能主要是使用简短的无意义的字母组合来对代码中的类,字段,方法和属性进行重命名,但它无法对字符串进行混淆,也就是说,使用ProGuard之后,我们还是可以看到反编译后代码中完整的字符串定义,为了实现更高级的混淆和加密功能,我们可以选择商业版本的ProGuard-DexGuard,DexGuard对代码,资源,字符串,AndroidManifest.xml等进行了全面的加密和混淆,相比ProGuard,功能强大了不少。
对敏感信息进行伪装或者加密
虽然DexGuard功能强大,也能帮助我们对敏感字符串信息进行加密,但必需需要付费使用,并不是每个公司都会愿意付费,因此多数情况下,只能靠我们自己对Java代码中的敏感信息进行伪装或者加密,以加大第三方破解的难度,最简单的我们可以使用Base64对字符串进行编码,然后将编码后的字符串和另外一串密钥进行异或操作,从而得到伪装后的字符串。
敏感信息隐藏在原生函数库中(.so文件)
为了增大第三方获取敏感信息的难度,我们可以进一步把敏感信息的存放从Java层下移到Native层,也就是存放在.so文件中,然后通过jni封装对敏感信息的获取接口,至于敏感信息在C/C++层如何存放,我们可以重复Java层的伪装和加密方式,另外可以在C/C++层通过花指令的方式来使得反汇编.so文件的时候出错,来增加.so文件被破解的难度
对APK进行加固处理
APK的加固处理极大的增加了反编译的难度,经过加固平台的加固后,想使用普通的dex2jar,Apktool等工具进行反编译几乎都是失败的,这使得普通开发者再也无法轻易的窥视发布在应用市场上面的APP的代码或者资源了
网友评论