- A+
“Android 应用”的安全漏洞,说到 Android 应用的安全漏洞,如果抛开系统设计问题,其主要原因是开发过程当中疏漏引起的。但其实也并不能把这些责任都怪在程序猿头上。所以本答案也将会对 Android 系统设计以及生态环境做一些阐述。(如果想了解 Android 恶意软件的情况,那就需要另开题目了。)
1. 应用反编译
漏洞:APK 包非常容易被反编译成可读文件,稍加修改就能重新打包成新的 APK。
利用:软件破解,内购破解,软件逻辑修改,插入恶意代码,替换广告商 ID。
建议:使用 ProGuard 等工具混淆代码,重要逻辑用 NDK 实现。
例子:反编译重打包 FlappyBird,把广告商 ID 换了,游戏改加插一段恶意代码等等。
2. 数据的存储与传输
漏洞:外部存储(SD 卡)上的文件没有权限管理,所有应用都可读可写。开发者把敏感信息明文存在 SD 卡上,或者动态加载的 payload 放在 SD 卡上。
利用:窃取敏感信息,篡改配置文件,修改 payload 逻辑并重打包。
建议:不要把敏感信息放在外部存储上面;在动态加载外部资源的时候验证文件完整性。
漏洞:使用全局可读写(MODE_WORLD_READABLE,MODE_WORLD_WRITEABLE)的内部存储方式,或明文存储敏感信息(用户账号密码等)。
利用:全局读写敏感信息,或 root 后读取明文信息。
建议:不适用全局可读写的内部存储方式,不明文存储用户账号密码。
3. 密码泄露
漏洞:密码明文存储,传输。
利用:
-
root 后可读写内部存储。
-
SD 卡全局可读写。
-
公共 WiFi 抓包获取账号密码。
建议:实用成熟的加密方案。不要把密码明文存储在 SD 卡上。
4. 组件暴露 (Activity, Service, Broadcast Receiver, Content Provider)
漏洞:
-
组件在被调用时未做验证。
-
在调用其他组件时未做验证。
利用:
-
调用暴露的组件,达到某种效果,获取某些信息,构造某些数据。(比如:调用暴露的组件发短信、微博等)。
-
监听暴露组件,读取数据。
建议:验证输入信息、验证组件调用等。android:exported 设置为 false。使用 android:protectionLevel="signature" 验证调用来源。
5. WebView
漏洞:
-
恶意 App 可以注入 JavaScript 代码进入 WebView 中的网页,网页未作验证。
-
恶意网页可以执行 JavaScript 反过来调用 App 中注册过的方法,或者使用资源。
利用:
-
恶意程序嵌入 Web App,然后窃取用户信息。
-
恶意网页远程调用 App 代码。更有甚者,通过 Java Reflection 调用 Runtime 执行任意代码。
建议:不使用 WebView 中的 setJavaScriptEnabled(true),或者使用时对输入进行验证。
6. 其他漏洞
-
ROOT 后的手机可以修改 App 的内购,或者安装外挂 App 等。
-
Logcat 泄露用户敏感信息。
-
恶意的广告包。
-
利用 next Intent。
7. 总结
Android 应用的漏洞大部分都是因为开发人员没有对输入信息做验证造成的,另外因为 Intent 这种特殊的机制,需要过滤外部的各种恶意行为。再加上 Android 应用市场混乱,开发人员水平参差不齐。所以现在 Android 应用的漏洞,恶意软件,钓鱼等还在不断增多。再加上 root 对于 App 沙箱的破坏,Android 升级的限制。国内的 Android 环境一片混乱,惨不忍睹。所以,如果想要保证你的应用没有安全漏洞,就要记住:永远不要相信外面的世界。
soure:https://www.zhihu.com/question/22933619
Activity
漏洞
越权绕过漏洞
原理:
没有对调用activity的组件进行权限验证,就会造成验证的安全问题。
防护:
1. 私有activity是相对安全的,设置exported为false。
2. 公开activity应:谨慎处理接收的intent;返回数据不应包含敏感信息;不应发送敏感信息;收到返回数据时谨慎处理。
钓鱼欺诈劫持
原理:
启动一个activity时,加入标志位FLAG_ACTIVITY_NEW_TASK,能够使被启动的activity立马呈现给用户,可用于钓鱼欺诈。
防护:
1. 如果当前程序进入后台那么对用户进行提示该程序已经进入后台运行。
隐式启动intent
包含敏感数据
原理:
当存在两个应用具有相同的隐式启动activity需要的action时,一个应用的activity是导出的,一个应用的activity是不被导出的,那么当触发该action时,将会弹出选择哪一个activity的界面,进而能够启动那个不被导出的activity。(老版本才有,新版本已修复此漏洞,经测4.4版本无此漏洞)。
拒绝服务
原理:
本地组件启动时没有对Intent.getXXXExtra()获取或处理的数据进行异常捕获,从而导致攻击者可通过向受害者应用发送空数据、异常或者畸形数据来使该应用crash的目的。
防护:
1. 谨慎处理接收的intent以及其携带的信息。
2. 对接收到的任何数据做try catch处理,对于不符合预期的数据做异常处理,异常包括但不限于:空指针异常、类型转换异常、数组越界访问异常、类未定义异常、序列化反序列化异常(getSerializableExtra、getParcelableExtra)
Service
漏洞
权限提升
原理:
当一个具有高权限的service是被导出的时,如果没对调用这个Service进行权限限制和调用者的身份验证时,那么恶意的app将具有调用高权限的service的能力来执行高权限行为等。
Service
劫持
原理:
对于隐式启动的service,当存在同action名触发条件的service时,先安装应用的service优先级高,即使本应用使用startservice想要启动本应用的未导出的隐式service时也会被先安装的其他app的service劫持,因此想要劫持某个隐式启动的service时,只需要更早的在android系统中安装同action名的隐式启动的servic。(经测试,android4.4版本也有此问题;android5.0之后启动隐式的service时需要指明包名,因此理论上可以避免劫持的问题)。
消息伪造
原理:
对于被导出的service具有接收消息并进行相应操作时,如果不加权限控制和调用者的身份验证,那么将有可能具有消息伪造的安全隐患。
拒绝服务
原理:
同Activity漏洞->拒绝服务->原理
防护:
同Activity漏洞->拒绝服务->防护
Service
安全防护
1. 私有的service尽量不定义intent-filter并且设置exported为false。
2. 公开的service设置exported为true。
3. 尽量用显示的方式启动service。
4. 合作service需对合作方的app签名做校验。
5. Service接收到的数据需要谨慎处理。
6. 内部service需使用签名级别的protectionLevel来判断是否为内部应用调用。
7. Service不应在onCreate时决定是否提供服务,应在onStartCommand/onBind/onHandleIntent等方法被调用时做判断。
8. 当service有返回数据时,应判断接收数据的组件是否有信息泄露的风险。
9. 尽量不发送敏感信息。
Broadcast Receiver
漏洞
敏感信息泄露
原理:
发送intent的时候没有明确指定接收者,而是简单的通过action进行匹配,而如果这个intent里包含敏感数据,那么恶意应用就可以注册一个广播接收者,嗅探并且拦截这个广播并且窃取敏感数据。
防护:
使用LocalBroadcastManager来注册和发送广播只能被app自身广播接收器接收。
权限绕过漏洞
原理:
使用Context.registerReceiver()动态注册的广播默认是导出的,如果导出的BroadcastReceiver没有做权限控制,导致其可以接收一个外部可控的url、命令等信息来执行特定的功能,那么攻击者可以利用应用的这些功能来执行越权操作。
防护:
使用LocalBroadCastManager来动态注册广播,其有以下三点优势:
1. 不必担心敏感数据泄露,通过这种方式发送的广播只能应用内接收。
2. 不必担心安全漏洞被利用,因为其他应用无法发送广播给该应用。
3. 它比系统的全局广播更高效。
消息伪造
原理:
对于必须暴露的Receiver来说,如果其对外接收Intent而没有进行权限控制和身份验证,那么攻击者则能够伪造Intent中的消息。
防护:
自定义声明权限,其protectionLevel为signature,在该暴露的Receiver中使用android:permission对其进行自定义权限限定,那么当其他应用如果和该应用的签名不一致时将无法申请该自定义权限,那么其他应用发出的不具有该自定义权限的同action广播是不会被该暴露的Receiver接收到的。
拒绝服务
原理:
同Activity漏洞->拒绝服务->原理
防护:
同Activity漏洞->拒绝服务->防护
Broadcast
安全防护
1. 私有广播接收器设置exported为false,尽量不配置intent-filter。
2. 私有广播尽量使用LocalBroadcastManager动态注册和使用。
3. 暴露的广播接收器需要对数据来源进行权限控制和身份验证。
4. 广播接收器对于接收的数据要谨慎地使用多种异常来控制数据处理。
5. 发送广播时如果包含敏感数据则需要显示意图和指定接收者包名,setPackage()
Content Provider
漏洞
信息泄露
原理:
如果没有对Content Provider的权限做好控制,那么恶意程序有可能利用这种方式读取APP的敏感数据。
防护:
1. minSdkVersion不低于9.
2. 不向外部app提供数据的私有content provide,应设置exported为false。
3. 使用protectionLevel为signature来进行权限控制。
4. 公开的content provider确保不存储敏感数据。
SQL
注入漏洞
原理:
对Content Provider进行增删改查操作时,程序没有对用户的输入进行过滤,未采用参数化查询的方式,可能导致sql注入攻击。这样攻击者可以精心构造selection、projection参数等sql语句组成部分,实现在未授权的情况下从content provider获取更多的信息。
防护:
1. 实现健壮的服务端校验。
2. 使用参数化查询语句,比如SQLiteStatement。
3. 避免使用rawQuery()。
4. 过滤用户的输入。
目录遍历漏洞
原理:
ContentProvider.openFile()方法使用不当将导致该漏洞,Uri.getPathSegments()这个API设计的时候未考虑输入数据会包含编码后的url的问题。
防护:
首先对paramUri解码,文件创建后再通过调用File.getCanonicalPath()来获取文件或文件夹的绝对路径,最后校验生成的文件是否数据某个文件夹下面。
信息泄露漏洞
敏感信息:
密码、手机号、快捷支付手机号、Email、身份证、银行卡、CVV码、有效期。
LogCat
输出敏感信息
原理:
1. 应用层Log敏感信息输出。
2. 应用层System.out.println敏感信息输出。
3. 系统某些异常的Log输出。
4. Native层敏感Log输出。
防护:
1. Eclipse中配置ProGuard实现release版apk实现自动删除Lod.d/v等。
2. 使用自定义LogCat类,上线前关闭Logcat开关。
敏感数据明文存储于Sdcard
原理:
Android系统的文件一半存储在sdCard和应用的私有目录下面,有些应用把敏感数据保存在了sdcard中,存在其数据被污染和替换的风险。
防护:
应用的敏感数据严禁存储在sdcard中。
数据库敏感数据明文存储
原理:
Database配置模式安全风险主要在于开发者在创建数据库(Database)时没有正确的选取合适的创建模式(MODE_PRIVATE, MODE_WORLE_READABLE, MODE_WORLD_WRITEABLE)进行权限控制,从而导致敏感信息泄露或者数据被篡改。
防护:
1. 敏感信息在数据库中需要加密存储,避免弱加密或者不加密的方式。
2. 对于敏感的数据库文件,不能使用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE的模式进行创建。
Shared Preference
全局可读写
原理:
开发者在创建文件时没有正确的选取合适的创建模式(MODE_PRIVATE, MODE_WORLE_READABLE, MODE_WORLD_WRITEABLE)进行权限控制,明文存储敏感信息。
防护:
1. 避免使用MODE_WORLD_READABLE或者MODE_WORLD_WRITEABLE的模式创建进程间通信的shared preferences文件。
2. 重要敏感信息应该加密存储,因为如果android系统被root之后,app的私有目录也将能够被外部程序访问。
3. 避免滥用android:sharedUserId属性,在使用该属性的时候,不要对应用使用测试签名,否则其他具有相同签名的同sharedUserId的应用将能访问到该应用的内部存储。
4. 使用Secure Preferences等第三方加固库进行存储。
敏感信息硬编码
原理:
开发者在开发过程中把重要信息硬编码到apk文件中,导致攻击者可以通过逆向apk的方式得到重要敏感信息。
防护:
避免硬编码敏感信息。
HTTP
明文传输敏感信息
原理:
Http协议是明文传输数据的,当其传输敏感数据时将有可能被攻击者窃取到。
防护:
1. 敏感信息如果使用http协议传输,那么要对其进行加密,尽量使用非对称加密算法。
2. 使用https协议传输数据。
权限安全漏洞
权限泄露漏洞
原理:
主要存在于某些具有高权限操作的组件被导出,而系统没有进行严格的身份验证和权限控制而导致的其他应用可以利用该组件而产生越权操作的行为。
防护:
1. 设置相应的组件为非导出的,也就是私有的。
2. 如果组件必须被导出,那么通过设置自定义权限的方式来达到只有同签名的应用才可访问的效果,参考Broadcast Receiver漏洞->消息伪造->防护。
默认设置漏洞
AndroidManifest.xml
配置文件中的默认设置
allowBackup
默认设置风险
原理:
AndroidManifest文件中的allowBackup属性默认值为true,其为应用程序提供了数据备份和恢复的功能,但是这样攻击者就可以利用这种功能获取敏感信息、伪造身份、直接对服务器攻击等。
防护:
显示设置android:allowBackup=false,使用android:restoreAnyVersion的默认值。
Debuggable
默认设置风险
原理:
android:debuggable属性用于指定应用程序是否能够被调试,如果设置其为true,那么其将能够被java调试工具(jdb)调试,信息和代码都将可能会被获取和修改。
防护:
系统默认其为false,使用系统默认设置。
组件默认导出风险
原理:
1. android:exported=true表示当前组件可以被另一个application的组件启动;false表示当前组件只会被当前application或者拥有同样user ID的application启动。
2. 如果组件总具有隐式启动的intent-filter标签,那么其默认的exported=true,否则默认值为false。
3. 主activity被认为不具有风险。
防护:
1. 没必要导出的组件设为私有,exported=false。
2. 必须导出的组件要对该组件进行权限控制。
WebView
默认设置
原理:
部分函数默认设置存在风险:
1. setSavePassword(boolean):webview默认开启密码保存功能mWebView.setSavePassword(true),如果该功能未关闭,在用户输入密码时会提示用户是否保存密码,如果是,那么密码将会被明文保存到应用的私有目录的databases目录下的webview.db文件中。如果手机被root,那么将有信息泄露的风险。
2. setAllowFileAccess(boolean):webview默认mWebView.setAllowFileAccess(true),在File域下能够执行任意的js代码,能够对私有目录文件进行访问,未对file:///形式的URL做限制,导致隐私信息泄露、cookie信息泄露等。
3. android4.1版本以前默认setAllowFileAccessFromFileURLs(true)/setAllowUniversalAccessFromFileURLs(true),即允许通过file域URL中的js读取其他本地文件,在之后的版本默认为false;当设置了setAllowUniversalAccessFromFileURLs(true),那么setAllowFileAccessFromFileURLs函数将失效。
4. setAllowContentAccess(boolean):其表示是否允许在WebView中访问内容URL(Content Url),默认允许。内容Url访问允许WebView从安装在系统中的内容提供者载入内容,比如让WebView访问ContentPrivider存储的内容。
防护:
如无必要,则需要手动将以上几个函数设置其值为false。
WebView
漏洞
远程代码执行漏洞
原理:
1. 在android4.4版本以下:API16及以下,直接调用add方法将会引入searchBoxJavaBridge_接口而引发该漏洞,主要原因是系统没有对允许反射调用的公有函数做限制,导致攻击者可以利用暴露在js中的接口,通过反射的方式无限制的调用其他java类提供的公有方法,导致权限泄露。类似的危险函数还有accessibility,accessibilityTraversal。
2. 在android4.4版本及以上,该漏洞发生的原因都是发生在chromium v8内核中。
防护:
除了把自己应用里暴露的js接口做安全处理,还要移除系统添加的三个接口:searchBoxJavaBridge_、accessibility、accessibilityTraversal。
UXSS
漏洞
原理:
通用型跨站脚本(UniversalCross-Site Scripting),主要利用浏览器及插件的漏洞来构造跨站条件以执行恶意代码。其漏洞对象为浏览器及其插件,其影响范围为在浏览器中访问的所有站点。
防护:
及时升级手机webview组件。
WebView
设置方面的安全风险
1. set,如无必要设置其为false。
2. setPluginState(enum),如无必要设置其为OFF。(ON/ON_DEMAND/OFF)
3. 同默认设置漏洞->WebView默认设置。
WebView
忽略证书错误漏洞
原理:
WebView组件加载网页发生证书认证错误时,会调用WebViewClient类的onReceivedSslError方法,如果该方法实现调用了handler.proceed()来忽略该证书错误,则会受到中间人攻击的威胁,可能导致隐私泄露。
防护:
不调用android.webkit.SslErrorHandler的proceed方法,采用默认的处理方法SslErrorHandler.cancel(),停止加载问题页面。
同源策略绕过
原理:
当应用程序使用WebView并支持File域时,JavaScript的延时执行能够绕过file策略的同源检查,并能够访问受害应用的所有私有文件。具体来说即通过WebView对Javascript的延时执行和将当前html文件删除并软连接指向其他文件就可以读取到被符号链接所指的文件,然后通过js再次读取html文件即可获取到被符号链接所指的文件。
防护:
1. 将不必要导出的组件设置为不导出的。
2. 如果应用需要导出的组件包含WebView,要禁止使用File域协议:myWebView.getSettings.setAllowFileAccess(false)。
3. 如果必须使用File域协议,要禁止File协议调用。
4. 如果必须调用JavaScript,那么需要谨慎判断加载的file是否为敏感的file。
WebView
防护
1. 手机厂商把手机内置的webview与google保持更新一致。
2. 手机厂商把手机内置的浏览器漏洞修补程度要与Google官方保持一致,并且检测个性化自定义暴露的API接口。
3. 手机浏览器厂商浏览器漏洞修补程度要与Google官方保持一致,并且检测个性化自定义暴露的API接口。
4. APP开发人员注意webview各项默认设置。
5. 用户随时把手机内置webview以及浏览器更新到最新版本。
Https
通信漏洞
忽略SSL
证书校验
原理:
在自定义实现X509TrustManager时,checkServerTrusted中没有检查证书是否可信,导致通信过程中可能存在中间人攻击,造成敏感数据劫持。
防护:
在自定义实现X509TrustManager时,在checkServerTrusted中对服务器信息进行严格校验。
忽略域名校验
原理:
1. 在自定义实现HostnameVerifier时,没有在verify中进行严格证书校验,导致通信过程中可能存在中间人攻击,造成敏感数据劫持。
2. 在setHostnameVerifier方法中使用ALLOW_ALL_HOSTNAME_VERIFIER,信任了所有Hostname,也有中间人攻击风险。
防护:
1. 自定义实现HostnameVerifier时,在verify中对Hostname进行严格校验。
2. 在setHostnameVerifier方法中使用STRICT_HOSTNAME_VERIFIER进行严格域名校验。
Socket
远程连接漏洞
原理:
如果手机应用配置了服务端并开放了某个端口(TCP/UDP),但是缺少对客户端的身份验证或者存在权限控制漏洞,那么将会导致攻击者利用此端口获取其支持的所有功能。
防护:
1. 使用公私玥密码体制在客户端对请求进行私玥加密,在服务端使用公玥进行签名验证,但是这样无法保证请求内容的私密性,只是提供了不可伪造的请求信息。
2. 不使用这种方式来控制应用的功能,改变设计。
3. 不使用0.0.0.0的监听ip地址,而使用127.0.0.1的本地地址,或者给相关的动作执行加入用户安全提示,用户允许才可以进行响应操作。
白名单绕过漏洞
签名白名单绕过
原理:
1. Apk中的META-INF文件夹下的三个文件:
a) MANIFEST.MF存储的是每一个文件对应的SHA1(或者SHA256)消息摘要算法提取出的摘要然后进行BASE64编码。
b) CERT.SF存储的是MANIFEST.MF文件的整体SHA1值,经过BASE64编码后记录在其主属性块的SHA1-Digest-Manifest属性值下;逐条计算MANIFEST.MF文件中的每一个块的SHA1,经过BASE64编码后记录在其同名块的SHA1-Digest属性值下。
c) CERT.RSA存储的是对CERT.SF文件的签名和包含公钥信息的数字证书,其满足PKCS7格式。签名算法包括DSA/RSA/EC三种,分别对应CERT.DSA/CERT.RSA/CERT.EC。
2. Android安装程序在校验签名文件时,android4.x版本只会校验META-INF文件夹下读取到的第一个签名文件,如果验证错误则退出;android5.x版本会逐个校验META-INF文件夹下的签名文件,只要有一个签名验证成功则通过。
3. 风险在于若安全评估软件使用证书白名单机制,可能只会读取验证一个签名文件,而没有检查此证书的有效性与合法性。那么当存在多个签名文件的恶意应用,分别是有效的但不合法的和无效的但合法的签名文件,在android5.x版本上安装软件时由于存在有效的签名文件则能够安装成功,而安全软件检查签名的时候如果只检查了一个无效的但合法的签名文件时将通过安全验证,而此时产生绕过漏洞。
防护:
安全软件在评估apk文件时要验证所有签名文件的有效性与合法性,分别作出对应的判断。
URL
白名单绕过漏洞
原理:
应用在打开外部传入的URL时,对域名校验时如果使用系统提供的getHost函数获取域名后进行字符串比较时而产生的漏洞,因为该系统函数设计存在缺陷,其可以被绕过。
绕过方式1:url地址变形,示例http://192.168.0.2\.126.com/index.html,其使用getHost得到的域名为192.168.0.2\.126.com
会很容易被判断为正常域名,然而android的webview会将其解析为http://192.168.0.2/.126.com/index.html
,那么该地址或许会带来风险。
绕过方式2:利用url跳转,示例http://hao.126.cn/?c=redirect&url=http://aaa.bbb.cn/123
,其通过getHost得到的域名也是正常的,但跳转访问的地址却存在风险的可能。
防护:
谨慎处理对传入URL的验证,建议采用正则表达式匹配的方式。
程序自升级漏洞
原理:
Apk自升级过程中,如果没有注意安全开发规范,导致其在下载apk的过程中被攻击者中间人劫持,替换了apk文件。
App升级流程
存在隐患
漏洞危害
升级API
升级API未加密
返回恶意下载地址,下载恶意APK
下载API
下载API未加密
下载文件被劫持,下载恶意APK
程序安装API
APK本地路径篡改
安装错误的APK
防护:
1. 升级API使用HTTPS。
2. 下载API使用HTTPS。(如果使用http,下载地址和md5值都可以被劫持的)
3. 安装apk时需要对apk文件进行包名和签名验证。
插件动态加载安全漏洞
原理:
1. Apk文件中的classes.dex文件相当于可执行文件,当app运行后系统会对classes.dex做优化,生成其对应的odex格式文件,也就是可执行文件的换成代码文件。
2. Android4.1之前的版本提供的类加载器DexClassLoader可以在运行时动态加载dex文件生成的odex文件存储在应用的非私有目录中,之后的版本只能保存在应用的私有目录中。
3. 应用程序在加载已有的odex文件时只验证了odex文件中的modTime和crc,未作其他校验。
4. 风险在于攻击者可以精心构造恶意odex文件利用其他方式替换应用程序原有的odex文件,只需要保证恶意的odex文件中modTime和crc值能通过校验即可,执行了恶意的odex文件将会导致恶意代码注入等问题。
防护:
1. 每次执行程序的时候重新生成odex文件。
2. 存储原有odex文件的信息用于下次加载的完整性和防篡改校验。
其他漏洞
串谋攻击
原理:
程序1的组件在没有权限的情况下,利用程序2的组件进行越权绕过执行操作。
防护:
1. 使用Context.checkCallingPermission()和Context.enforceCallingPermission()来确保调用者拥有相应的权限。
2. 校验应用的permission保护级别是否与系统中已定义的permission保护级别一致。(PackageManager.getPackageInfo.permissions[i].protectionLevel ==PackageManager.getPermissionInfo())
Zip
解压缩漏洞
原理:
当压缩文件中具有../../../等目录跳转符时,会产生目录穿越风险,当解压该文件的应用具有某些路径的写权限时,攻击者可以构造指定的目录对原有文件进行替换,比较常见的是so文件或者odex文件的恶意替换。
防护:
解压时过滤../跳转符。(ZipEntry.getName().contain(“../”)?)
source:http://blog.sina.com.cn/s/blog_83f3c04c0102xeow.html
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫