一、前言
本篇是Android SDK开发艺术探索系列的第五篇文章。介绍了一些SDK开发中安全方面的知识,包括资源完整性、存储安全、权限校验、传输安全、代码混淆等知识。通过基础的安全配置为SDK保驾护航,探索SDK开发在安全方面的最佳实践。
防杠说明:本人认同前端没有绝对的安全,基本我们公开谈论的大部分安全策略都可以绕过,但这不能成为我们忽视安全的理由。
二、安全概览
![](https://i-blog.csdnimg.cn/blog_migrate/725aaed9e416a5d90ccc15e1e6ced364.png)
三、资源安全
3.1、完整性检查
SDK资源完整性检查,是指在SDK开发中,对于AAR包的完整性做一些检查。实际上,对于资源的完整性、有效性检查,通常是核对其文件的摘要。SDK包也是如此,可以在发布AAR时同时发布该文件的摘要,用于核对校验。
这里也介绍简单一下另一个思路,即从SDK代码中检测资源的方法。众所周知,AAR在编译的时候是完全被合并APK中了,校验AAR摘要的思路可以说就这样断了。但是我们可以通过校验AAR中的资源,如raw、assets目录下的文件。由于这两个目录下的文件在编译时不会被压缩,因此编译前后文件内容不会改变,其摘要也不会变,适合用来在资源校验。
至于摘要检验方案,可以简单在Java层面做,也可以在so里做,校验的时机与策略就更多选择了,这里就不展开讲了。
3.2、警惕资源覆盖造成的安全问题
Android Studio 会将Library模块中的资源与Application模块的资源合并。App Module的资源将会覆盖Library Module中的同名资源。正因为有此特性,我们不得不对SDK的资源进行保护,避免由于一些意外因素导致资源覆盖,从而引起与预期不一致的软件行为。
我们提到的资源主要包括常见res、assets目录下所有的文件、在对文件或资源进行命名时,务必添加唯一性的前缀或其他唯一性的命名方案。
凡事都有两面性,这一特性也为我们替换SDK资源,进行个性化改造提供了一种思路。
四、存储安全
在安全存储这方面,主要还是考验开发者的意识,看到这里的朋友不妨回头检查下手头的陈旧代码,说不定就有敏感信息明文存储,直接裸奔的问题。
4.1、SP安全存储
SharedPreferences采用xml文件格式来保存数据, 该文件所在目录位于/data/data//shared_prefs/,如果直接将账号密码或个人敏感信息存储进去,手机root后就可以轻松获取。因此,存储时尽量考虑简单做一层加密逻辑。无论是SharedPreferences还是数据库,都要避免明文敏感数据存储。
另外,SharedPreferences存储一些配置信息时也要配置好访问权限,如私有的访问权限 MODE_PRIVATE,避免配置信息被篡改。
4.2、SO安全存储
由于Java是解释性语言,而Java的混淆是没法混淆常量的。但是我们又不可避免地在前端存储一些密钥对,那么怎么存储才比较安全呢?建议往SO里存,不仅需要把密钥存储于SO,还需要把加解密逻辑甚至传输逻辑放置于SO,才能较好地保护代码逻辑。
五、传输安全
5.1、网络安全配置
该特性让应用可以在一个安全的声明性配置文件中灵活的自定义其Https网络安全设置,而无需修改应用代码,满足更高的安全性要求。
在AndroidManifest.xml中配置networkSecurityConfig:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... ><application android:networkSecurityConfig="@xml/network_security_config"... >...</application>
</manifest>
network_security_config文件如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><domain-config><domain includeSubdomains="true">example.com</domain><trust-anchors><certificates src="@raw/my_ca"/></trust-anchors></domain-config>
</network-security-config>
以 PEM 或 DER 格式将自签署或非公共 CA 证书添加到 res/raw/my_ca
。回想起年前听到渗透测试结果时的恐惧,好家伙,自己装了个证书…不过Android7.0以上已经默认不信任用户手动安装的证书了。
这部分更多细节、功能可以参考官方文档网络安全配置
5.2、安全环境检测
我们这里说提及的安全环境主要是指有可能对我们的业务逻辑产生影响的环境,比如挂了VPN代理、Root了手机/安装了Xposed、应用被多开、模拟器环境…
5.2.1、VPN代理检测
检测当前连接的网络是否开启VPN
//检测系统是否正在使用vpn连接
public boolean isVpnOn(Context context) {boolean isVpnOn = false;ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {Network activeNetwork = connectivityManager.getActiveNetwork();NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(activeNetwork);isVpnOn = caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);}else {isVpnOn = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_VPN).isConnectedOrConnecting();}Log.i(TAG, "Is VPN On: " + isVpnOn);return isVpnOn;
}
5.2.2、Root/Xposed/反调试/应用多开/模拟器检测
关于Root/Xposed/反调试/应用多开/模拟器的检测方法,这里推荐一个很好用的第三方库EasyProtector 具体API这里就不贴了,参考作者的项目即可。
六、混淆与配置
6.1、手动集成
一般我们对接第三方SDK时,都会有一个混淆配置。同理,我们在发布SDK时也可以参考这类设计,提供SDK中不需要混淆的代码配置,在对接文档中集成即可。
6.2、SDK内置
为了提高接入体验,能否将SDK中的混淆配置也打包进aar中,让项目自动配置SDK的混淆文件呢?答案是肯定的,我们可以指定consumerProguardFiles
属性,自定义引入的混淆规则,即可将*.pro
文件打包进入aar
中,项目打包时就会自动合并该配置文件。 值得一提的是该属性只镇对library有效,对app无效。
consumerProguardFiles
配置如下:
android {compileSdkVersion 29buildToolsVersion "29.0.3"defaultConfig {minSdkVersion 21targetSdkVersion 29versionCode 1versionName "1.0"consumerProguardFiles "proguard-rules.pro"//将Library混淆配置打包进AAR,将在app构建时参与混淆testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled trueshrinkResources falsesigningConfig signingConfigs.releaseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falseshrinkResources falsesigningConfig signingConfigs.releaseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}
6.3、混淆的那些坑
以上配置看似简单,但却潜在一些坑,在最新的4.x的Android Studio中我们新建一个library module,会自动创建出两个***rules.pro
文件,其中consumer-rules.pro
,自动被defaultConfig
下的consumerProguardFiles
所引用; proguard-rules.pro
,自动被buildType下的proguardFiles
引用。
![](https://i-blog.csdnimg.cn/blog_migrate/29bc38d57dd56176c20613f6199e06c7.png)
那么这两者有何差别?为什么要区分开两个文件来写呢?经过充分验证,结论就是:
1、defaultConfig
下的consumerProguardFiles
配置的*.pro
文件将会在library module打包成aar时,以proguard.txt的形式存在,将参与到集成这个arr的App编译中,但不参与这个library module打包成aar的编译过程;
2、buildType
下proguardFiles
配置的*.pro
文件作用与library module打包成aar的编译过程,仅作用于本module的编译混淆过程。
在实际操作中,直接将consumerProguardFiles
配置的*.pro
文件改为proguard-rules.pro
,这样就能粗暴地解决掉aar编译时的混淆与apk编译时的混淆了。
但是需要特别注意的是,根据我们SDK开发设计中的最小可用性原则,应该谨慎添加混淆规则,如无必要,勿增规则,避免对集成该aar项目的正常混淆造成干扰。
七、结语
本篇主要介绍了一些SDK安全与校验方面的知识。安全是一种意识,难的不是安全,是没有意识。正如开篇提到的前端没有绝对的安全,但是安全也不能仅依靠前端,它应该是多端协同下的多层级、系统级的安全。对于开发者来说,应该有所作为,毕竟多一道防线就多一点安全。一个开发者应该拥有基础的安全意识,才能尽量避免安全事故。
![](https://i-blog.csdnimg.cn/blog_migrate/08c3b846393bdaea6409358cbf194580.jpeg)