如何让你的Android应用更安全

简介: 作为Android应用开发者,开发出一款用户喜欢、满意的应用是一件值得开心和满足的事情,而在功能强大的基础上,如何保证应用更安全也显得尤为重要。根据实际开发过程,我们将从以下几个最佳实践来让我们的应用“更加安全”。

如何让你的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是在传输层上层的协议,应用层的下层,作为一个安全套接层而存在,我们一般叫做传输层安全协议。

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为例来做说明:

httpsrequest111

如果使用系统默认的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校验证书:

getssl3

通过设置制定信任的证书锚点,仅对该证书及其签发的证书才会被信任:

getssl2

以上就是使用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 混淆

如果你不想开源你的应用,那么在应用发布前,就需要对代码进行混淆处理,这样即使应用被反编译,也难以阅读。混淆除可以增大反编译难度外,还具备减少应用体积、移除未被使用的类和成员以及优化字节码执行的功能。目前常用的混淆器包括ProGuardDexGuard以及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的安全性。本文内容如有偏颇,欢迎大家指正。

参考资料:

目录
相关文章
|
16天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
17天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
17天前
|
开发框架 安全 Android开发
探索安卓系统的新趋势:智能家居应用的蓬勃发展
随着智能家居概念的兴起,安卓系统在智能家居应用领域的应用日益广泛。本文将探讨安卓系统在智能家居应用开发方面的最新趋势和创新,以及其对用户生活的影响。
13 2
|
20天前
|
缓存 监控 Java
构建高效Android应用:从优化用户体验到提升性能
在竞争激烈的移动应用市场中,为用户提供流畅和高效的体验是至关重要的。本文深入探讨了如何通过多种技术手段来优化Android应用的性能,包括UI响应性、内存管理和多线程处理。同时,我们还将讨论如何利用最新的Android框架和工具来诊断和解决性能瓶颈。通过实例分析和最佳实践,读者将能够理解并实施必要的优化策略,以确保他们的应用在保持响应迅速的同时,还能够有效地利用系统资源。
|
21天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
25天前
|
编解码 算法 Java
构建高效的Android应用:内存优化策略详解
随着智能手机在日常生活和工作中的普及,用户对移动应用的性能要求越来越高。特别是对于Android开发者来说,理解并实践内存优化是提升应用程序性能的关键步骤。本文将深入探讨针对Android平台的内存管理机制,并提供一系列实用的内存优化技巧,以帮助开发者减少内存消耗,避免常见的内存泄漏问题,并确保应用的流畅运行。
|
18天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
23天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
17 4
|
1天前
|
缓存 移动开发 Android开发
构建高效Android应用:从优化用户体验到提升性能表现
【4月更文挑战第18天】 在移动开发的世界中,打造一个既快速又流畅的Android应用并非易事。本文深入探讨了如何通过一系列创新的技术策略来提升应用性能和用户体验。我们将从用户界面(UI)设计的简约性原则出发,探索响应式布局和Material Design的实践,再深入剖析后台任务处理、内存管理和电池寿命优化的技巧。此外,文中还将讨论最新的Android Jetpack组件如何帮助开发者更高效地构建高质量的应用。此内容不仅适合经验丰富的开发者深化理解,也适合初学者构建起对Android高效开发的基础认识。
2 0
|
1天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。
5 0