如何让你的Android应用更安全

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 作为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的安全性。本文内容如有偏颇,欢迎大家指正。

参考资料:

目录
相关文章
|
1月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
166 4
|
23天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
50 14
|
26天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
23天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
24天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
23天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
32 0
|
1月前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
1月前
|
存储 搜索推荐 Java
打造个性化安卓应用:从设计到实现
【10月更文挑战第30天】在数字化时代,拥有一个个性化的安卓应用不仅能够提升用户体验,还能加强品牌识别度。本文将引导您了解如何从零开始设计和实现一个安卓应用,涵盖用户界面设计、功能开发和性能优化等关键环节。我们将以一个简单的记事本应用为例,展示如何通过Android Studio工具和Java语言实现基本功能,同时确保应用流畅运行。无论您是初学者还是希望提升现有技能的开发者,这篇文章都将为您提供宝贵的见解和实用的技巧。
|
1月前
|
搜索推荐 开发工具 Android开发
打造个性化Android应用:从设计到实现的旅程
【10月更文挑战第26天】在这个数字时代,拥有一个能够脱颖而出的移动应用是成功的关键。本文将引导您了解如何从概念化阶段出发,通过设计、开发直至发布,一步步构建一个既美观又实用的Android应用。我们将探讨用户体验(UX)设计的重要性,介绍Android开发的核心组件,并通过实际案例展示如何克服开发中的挑战。无论您是初学者还是有经验的开发者,这篇文章都将为您提供宝贵的见解和实用的技巧,帮助您在竞争激烈的应用市场中脱颖而出。
|
1月前
|
算法 Java 数据库
Android 应用的主线程在什么情况下会被阻塞?
【10月更文挑战第20天】为了避免主线程阻塞,我们需要合理地设计和优化应用的代码。将耗时操作移到后台线程执行,使用异步任务、线程池等技术来提高应用的并发处理能力。同时,要注意避免出现死循环、不合理的锁使用等问题。通过这些措施,可以确保主线程能够高效地运行,提供流畅的用户体验。
64 2