如何让你的Android应用更安全
作为Android应用开发者,开发出一款用户喜欢、满意的应用是一件值得开心和满足的事情,而在功能强大的基础上,如何保证应用更安全也显得尤为重要。根据实际开发过程,我们将从以下几个最佳实践来让我们的应用“更加安全”。
1.避免暴露不必要的组件(android:exported属性)
android:exported是Android中四大组件Activity,Service,Provider,Receiver中都会有的一个属性,用于表示是否支持其他应用调用当前组件,即android:exported=true表示当前组件可以被其他App使用,而android:exported=false则表示当前组件仅支持在应用内部(当前App)使用。
exported属性的默认值四大组件略有不同:
- Activity/Service/Receiver:若设置了intent filter,则默认为true,否则为false。
- Provider:当Android sdk版本为16或更低版本时,默认值为true,如果是17及以上版本则默认为false。
所以我们需要根据自己的需求来进行设定android:exported属性,一般来讲,有如下三种情况:
- 不暴露组件:在此情况下组件仅限于同一App使用,如果未设置intent-filter,可以不设置exported属性(默认为false);若设置了intent-filter,则必须设置exported=false;
-
部分暴露组件:此情况下说明组件需要被部分“特定”App调用,则除了需要满足上述“内部使用”外,推荐调用的App与当前暴露组件的App使用同一uid:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... android:sharedUserId="xxx.xxx.xxx">
或通过对暴露的组件设置permission:
<activity android:name=".xxxActivity"
android:label="自定义permission"
android:permission="com.xxx.permission" >
<intent-filter>
<action android:name="android.xxx.action" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
以上两种方式既可满足暴露组件的需求,又可以保护数据安全。
- 完全暴露组件:即组件可以被任何App调用,可手动设置exported=true(或设置intent-filter),但需要注意针对暴露组件接收的Intent进行异常捕获,避免出现其他App传入异常Intent数据导致出现拒绝服务或crash。
##### 结论
针对四大组件,需要根据实际需求来针对android:exported属性进行设定,避免过分暴露组件导致敏感操作或钓鱼欺骗。
2.避免WebView使用漏洞
目前越来越多的App采用Hybrid方式进行开发,通过使用WebView组件来实现native与Js交互,而近年来爆出的WebView相关漏洞也是层出不穷,所以我们在使用WebView时要注意以下几点:
2.1 避免addJavascriptInterface接口引起远程代码执行漏洞
原因
由于JS可以通过addJavascriptInterface接口调用Android对象:
webView.addJavascriptInterface(new JSObject(), "myObj");
// 参数1:Android的本地对象
// 参数2:JS的对象
// 通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法
所以当JS拿到Android对象后,就可以调用Android对象中所有的方法,包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
解决办法
- API >= 17:Google 在 API 17(Android 4.2) 中规定允许被调用的函数必须以
@JavascriptInterface
进行注解,进而避免漏洞攻击。 - API < 17:需要采用拦截prompt()的方式进行漏洞修复。
2.2 searchBoxJavaBridge_、accessibility及accessibilityTraversal接口引起的远程代码执行漏洞
原因
- 在Android 3.0以下,Android系统会默认通过
searchBoxJavaBridge_
的Js接口给 WebView 添加一个JS映射对象:searchBoxJavaBridge_
对象 - 该接口可能被利用,实现远程任意代码。
解决办法
webview.removeJavascriptInterface("searchBoxJavaBridge_");
webview.removeJavascriptInterface("accessibility");
webview.removeJavascriptInterface("accessibilityTraversal");
2.3 WebView域控制不严格漏洞
原因
- setAllowFileAccess:Android中默认webView.getSettings().setAllowFileAccess(true),在file域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等。
- setAllowFileAccessFromFileURLs:在JELLY_BEAN(API=16)以前的版本默认是webView.getSettings().setAllowFileAccessFromFileURLs(true),允许通过file域url中的Javascript读取其他本地文件,在JELLY_BEAN及以后的版本中默认已被禁止。
- setAllowUniversalAccessFromFileURLs:在JELLY_BEAN以前的版本默认是webView.getSettings().setAllowUniversalAccessFromFileURLs(true),允许通过file域url中的Javascript访问其他的源,包括其他的本地文件和http,https源的数据。在JELLY_BEAN及以后的版本中默认已被禁止。
解决办法
通过以下设置,防止越权访问,跨域等安全问题:
setAllowFileAccess(false);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
2.4 WebView密码明文存储漏洞
原因
WebView默认开启密码保存功能,如果该功能未关闭,在用户输入密码时,会弹出提示框,询问用户是否保存密码,如果选择"是",密码会被明文保到 /data/data/com.package.name/databases/webview.db
解决办法
webView.setSavePassword(false)
3.使用Https进行网络请求
3.1 HTTPS 简介
HTTP协议是没有加密的明文传输协议,如果我们的应用使用HTTP传输数据,则会泄漏传输的内容,很容易被中间人劫持,修改传输内容。
HTTPS 全称 HTTP over SSL/TLS。SSL/TLS是在传输层上层的协议,应用层的下层,作为一个安全套接层而存在,我们一般叫做传输层安全协议。
对 HTTP 而言,安全传输层是透明不可见的,应用层仅仅当做使用普通的 Socket一样使用 SSLSocket 。
TLS是基于 X.509 认证,他假定所有的数字证书都是由一个层次化的数字证书认证机构发出,即CA。另外值得一提的是 TLS 是独立于 HTTP 的,任何应用层的协议都可以基于 TLS 建立安全的传输通道,如 SSH 协议。
3.2 数字证书与证书链
数字证书就是互联网通讯中标志通讯各方身份信息的一串数字,它是由权威机构——CA机构,又称为证书授权(Certificate Authority)中心发行的,而保障安全的公钥存储在数字证书中,此证书将用户的身份跟公钥链接在一起。CA必须保证其签发的每个证书的用户身份是唯一的。
链接关系(证书链)通过注册和发布过程创建,取决于担保级别,链接关系可能由CA的各种软件或在人为监督下完成。PKI的确定链接关系的这一角色称为注册管理中心(RA,也称中级证书颁发机构或者中间机构)。RA确保公钥和个人身份链接,可以防抵赖。如果没有RA,CA的Root 证书遭到破坏或者泄露,由此CA颁发的其他证书就全部失去了安全性,所以现在主流的商业数字证书机构CA一般都是提供三级证书,Root 证书签发中级RA证书,由RA证书签发用户使用的证书。
Web 浏览器已预先配置了一组浏览器自动信任的根 CA 证书。来自其他证书授权机构的所有证书都必须附带证书链,以检验这些证书的有效性。证书链是由一系列 CA 证书发出的证书序列,最终以根 CA 证书结束。
验证证书大致过程:HTTPS建立连接后,CA下发给客户端的证书是分层的证书链,要验证某一层证书是否确实由上一级CA发放需要验证附带在该证书上的数字签名(由上级CA通过签名函数及私钥生成的数字签名),数字签名的解密需要上级CA的公钥,这个公钥保存在证书链中上层证书中。而根证书是自己给自己签名,也就是根证书的签名是用自己保存的公钥来解密。这样就保证了最底层的网站证书确实是证书中标明的CA发放的。只有根证书可信,下级证书才可信。
3.3 使用HTTPS通信
我们以HttpURLConnection为例来做说明:
如果使用系统默认的SSL,那么就是假设一切CA都是可信的,可往往并非所有CA都可信,所以最好还是实用自定义信任策略。而SSL在校验时是通过X509ExtendedTrustManager进行校验的,即X509TrustManager:
public interface X509TrustManager extends TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
public X509Certificate[] getAcceptedIssuers();
}
最终校验服务器证书的过程会在checkServerTrusted方法中,如果校验没通过会抛出CertificateException,而此处需要特别注意:如果checkServerTrusted方法中什么都不做,则默认信任任何证书,无任何安全性可言,也就失去了校验的意义!千万不要这么做!
那么校验证书有两种方式:
直接通过TrustManager校验证书:
通过设置制定信任的证书锚点,仅对该证书及其签发的证书才会被信任:
以上就是使用HTTPS进行网络通信的一般过程。针对WebView中使用HTTPS的情况,此处不做更多说明,请查询相关资料。对于网络通信方面,通过https进行通信,将在很大程度上,提升我们应用通信的安全性。
4.增加应用被反编译(二次打包)的难度
APK被反编译是目前作为应用开发者比较头疼的一件事,我们虽然无法做到绝对的安全(不被反编译),但可以通过相关技术手段增加应用被反编译的门槛。
4.1 应用加固
笼统的说APP加固是指对原本容易暴露的程序和运行逻辑进行一定程度的保护,而不影响程序本身的运行结果。其本质就是在二进制程序中植入代码(加固),在运行时优先去的程序控制权做一些额外工作(去壳)。
APP加固一般分为:dex加固和so加固,由于dex反编译后的java代码可读性更强,所以目前普遍优先针对dex文件进行加密。
简单来说dex加固基本步骤为:将需要加密的Apk和自己的壳程序Apk,用加密算法对源Apk进行加密再将壳Apk进行合并得到新的Dex文件,最后替换壳程序中的dex文件即可,得到新的Apk,那么这个新的Apk我们也叫作脱壳程序Apk.它已经不是一个完整意义上的Apk程序了,他的主要工作是:负责解密源Apk.然后加载Apk,让其正常运行起来。关于加固有一篇不错的文章可以参考:Android中的Apk的加固(加壳)原理解析和实现
加固后的APP可以有效减少被反编译后二次打包,造成仿冒应用,被不法分子增加恶意代码后重新打包,造成影响厂商利益,威胁用户信息安全的行为。
4.2 混淆
如果你不想开源你的应用,那么在应用发布前,就需要对代码进行混淆处理,这样即使应用被反编译,也难以阅读。混淆除可以增大反编译难度外,还具备减少应用体积、移除未被使用的类和成员以及优化字节码执行的功能。目前常用的混淆器包括ProGuard,DexGuard以及DexProtector。
ProGuard是Android Studio自带的代码混淆工具。在创建新的Android Studio工程时会自动生成一个ProGuard配置文件。在工程中以proguard-rules.pro命名。
开启ProGuard:
android {
...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
}
}
}
注意proguard-rules.pro中,针对不需要进行混淆的类进行keep操作,避免程序运行异常,篇幅原因,更多资料,请自行查阅。
还有很多方面可以提高APP的安全等级,如存储加密,妥善保存应用签名等。安全无小事,作为应用开发者,应当把APP安全与功能开发放在同等地位,尽量在应用上线前通过各种安全平台对应用进行静态扫描及漏洞扫描,考虑使用加固平台对应用进行加固,用以提高APP的安全性。本文内容如有偏颇,欢迎大家指正。
参考资料:
- http://jaq.alibaba.com/community/art/show?spm=a313e.7916648.25000002.4.2fa45382T7vZns&articleid=457
- https://jaq.alibaba.com/community/art/show?articleid=993
- https://jaq.alibaba.com/community/art/show?articleid=545
- https://blog.uptech.team/how-to-make-your-android-application-secured-21c054b371e7
- http://blog.csdn.net/carson_ho/article/details/64904635