请选择 进入手机版 | 继续访问电脑版

[Android] Android开发 中关于组件导出的风险及防范

[复制链接]
查看51 | 回复10 | 2021-9-14 06:16:48 | 显示全部楼层 |阅读模式

前言

比年 来,移动APP存在一个非常的告急 的题目 就是安全题目 ,造成的后果有大概 是用户的隐私走漏 和财产丧失 等,对于一款成熟的APP或者是金融银行类APP,这无疑是最致命的,以是 对APP举行 有效 的防范也是很有必要。
近段时间,公司安排了某安全公司对我们的APP举行 了全方面的安全测试,根据文档检测结果 看,团体 上看还是很安全的,此中 有一项就是组件导出风险,接下来我们说说四大组件、组件导出必要性、风险以及怎样 防范。

一、四大组件

从事Android开辟 ,我们都知道Android有四大组件, 分别是:

  • 活动(Activity),用于表现功能,是用户操作的可视化界面,它为用户提供了一个完成操作指令的窗口;
  • 服务(Service),后台运行服务,不提供界面呈现;
  • 广播担当 者(Broadcast Receive),用于汲取 广播;
  • 内容提供者(Content Provider),支持多个应用中存储和读取数据,相当 于数据库。

从这些组件简单的先容 ,我们知道它们的告急 性,赋予了app更加丰富的功能,以是 这四大组件的安全性对我们app和用户来说就显得更加地告急 。

二、组件导出必要性

什么是组件导出呢?组件导出的意思就是组件可以被外部应用调用,我们可以在这四大组件声明的清单文件设置组件是否导出,如下:

  1. <activity
  2. android:exported="true"
  3. android:name=".other.ComponentActivity">
  4. </activity>
复制代码

或者:

  1. <activity
  2. android:name=".other.ComponentActivity">
  3. <intent-filter>
  4. <action android:name="android.intent.action.VIEW"/>
  5. </intent-filter>
  6. </activity>
复制代码

上面两种方式都是Activity组件导出的方式,重要 是exported的值",为true时表示导出,Activity中exported的默认值:

  • 没有intent filter时,默以为 false;
  • 有intent filter时,默以为 true

Broadcast Receive和Service的默认值都跟Activity的一样。

Content Provider中exported的默认值:

  •  当minSdkVersion或者targetSdkVersion小于16时,默以为 true
  • 大于17时,默以为 false

开辟 过程中,app会有一些特定需求会利用 到三方SDK,如微信分享、付出 、推送等功能,我们发现这里都有一个共同点,都会涉及到组件导出的题目 ,如微信的

WXEntryActivity:

  1. <!-- 微信分享 -->
  2. <activity
  3. android:name="${applicationId}.wxapi.WXEntryActivity"
  4. android:exported="true"
  5. android:launchMode="singleTask"
  6. android:theme="@android:style/Theme.Translucent.NoTitleBar" />
复制代码

如许 就会被安全机构检测出来的,假如 不设置WXEntryActivity为组件导出,微信分享等功能根本就调不起来,这是官方的写法,我们以为 这是必须要设置为组件导出,除非你把微信分享需求干掉,那业务不把你骂死;又或者是监听网络变化的广播汲取 器(7.0版本以上只能代码中动态注册才能汲取 该广播)、推送功能,集成过一些推送SDK都有印象,一些Service也会声明android:exported="true"等等。
这些无可避免的组件导出,我们可以回复安全机构:微信分享、推送等功能必须设置组件导出,以是 我们只有保证本身 的四大组件的设置,确保其是安全的,如许 才能确保app处于比较安全的状态,应付安全检测,给你的向导 一个交代。

三、组件导出风险

前面阐明 了组件的告急 性、组件导出,那么组件导出的风险是什么呢?

  • Activity作为构成 Apk的四个组件之一,是Android程序与用户交互的界面,假如 Activity打开了导出权限,大概 被体系 或者第三方的App直接调出并利用 。Activity导出大概 导致登录界面被绕过、拒绝服务攻击、程序界面被第三方恶意调用等风险。
  • Broadcast Receiver作为构成 Apk的四个组件之一,对外部变乱 举行 过滤汲取 ,并根据消息内容实行 相应 ,假如 设置了导出权限,大概 被体系 或者第三方的App直接调出并利用 。Broadcast Receiver导出大概 导致敏感信息走漏 、登录界面被绕过等风险。S
  • ervice作为构成 Apk的四个组件之一,一样平常 作为后台运行的服务进程 ,假如 设置了导出权限,大概 被体系 或者第三方的App直接调出并利用 。Service导出大概 导致拒绝服务攻击,程序功能被第三方恶意调用等风险。
  • Content Provider构成 Apk的四个组件之一,是应用程序之间共享数据的容器,可以将应用程序的指定数据集提供给第三方的App,假如 设置了导出权限,大概 被体系 或者第三方的App直接调出并利用 。Content Provider导出大概 导致程序内部的敏感信息走漏 ,数据库SQL注入等风险。

接下来以Activity导出为示例,阐明 下其风险,别的 组件类比就好。起首 Activity要在清单文件AndroidManifest.xml注册:

  1. <activity android:name="com.littlejerk.sample.other.WebActivity"/>
复制代码

Activity的启动通常有两种方法

  • 显式启动,必要 指定启动的Activity:
  1. Intent intent = new Intent(getContext(),WebActivity.class);
  2. intent.putExtra("URL","https://blog.csdn.net");
  3. startActivity(intent);
复制代码
  • 隐式启动,Intent中不再包含必要 启动的详细 的Activity类,而是通过Intent提供某些信息,体系 去检索符合启动意图的Activity,这里是通过意图过滤器声明Intent信息:动作(action)、数据(data)、分类(Category)、范例 (Type),组件(Component)、和扩展信息(Extra)。
  1. <!-- 通过隐式启动的方式需要在AndroidManifest.xml文件声明-->
  2. <activity android:name=".other.WebActivity">
  3. <intent-filter>
  4. <action android:name="com.littlejerk.sample.action.VIEW_URL" />
  5. <category android:name="android.intent.category.DEFAULT"/>
  6. </intent-filter>
  7. </activity>
  8. //调用方式启动WebActivity
  9. Intent intent = new Intent();
  10. intent.setAction("com.littlejerk.sample.action.VIEW_URL");
  11. intent.putExtra("URL","https://blog.csdn.net");
  12. startActivity(intent);
复制代码

利用 Action跳转,假如 有一个程序的AndroidManifest.xml中的某一个 Activity的IntentFilter段中 定义了包含了雷同 的Action,那么这个Intent就与这个目的 Action匹配。假如 这个IntentFilter段中没有定义 Type、Category,那么这个 Activity就匹配了。但是假如 手机中有两个以上的程序匹配,那么就会弹出一个对话框来提示阐明 。
上面说过有IntentFilter,假如 不指定android:exported,那么该值默以为 true,外部的应用通过隐式意图的方式也能将对应的组件启动起来。这种环境 我们就是我们说的组件导出,而导出则意味着很有大概 存在安全题目 ,接下来看下WebActivity页面:

  1. Intent intent = getIntent();
  2. String url = intent.getStringExtra("URL");
  3. UILog.e(TAG, url.charAt(0));
  4. mTvContent.setText(url);
复制代码

我们留意 到WebActivity只是汲取 一个URL并且表现 出来(没有加载这个URL),从这里我们可以看出URL并没有做参数检验,应用大概 会崩溃;由于 该页面又是可被三方应用调用的,这时间 假如 别人恶意传递一些不良的网页信息,那你这个应用不拦截就直接加载了,则这个应用有大概 就要下架了。

四、怎样 防范

我们以最常见的Activity为例阐明 了组件导出的风险,由于 这个URL参数是我们处理的,我们可以防止应用空指针非常 ,这没题目 ,但是上面也说假如 加载了不良URL呢?着实 组件导出的风险最根本缘故原由 是被别人调用了,那如许 有没有办法控制这个别人的范围,只答应 我们信任 的人去调用。
在这里不得不提Android的权限机制,Android的Permission检查机制是用来控制一个应用拥有哪些实行 权利。比方 应用拥有照相 权限才能拥有照相 权利,那么我们是否可以通过权限来控制一个应用是否有启动WebActivity的权利呢?
Android提供了自定义权限的本领 ,应用可以定义本身 的权限,如在清单文件中自定义一个permission:

  1. <permission
  2. android:label="允许打开WebActivity页面权限"
  3. android:name="com.littlejerk.sample.permission.WEB"
  4. android:protectionLevel="signature" />
复制代码

label:权限的形貌

name:该权限的名称,利用 该权限时通过名称来指定利用 的权限

protectionLevel:该权限受保护的等级,这很告急 ,它有三个等级

  • signature:署名 级别权限,即权限的定义方和注册方必须具有雷同 的署名 才有效
  • system:体系 级别权限,即权限的定义方和注册方必须为体系 应用
  • signatureOrSystem :同署名 或体系 应用,上述二者具备其一即可

权限定义完成,怎样 用它来保护暴露的组件呢,看下面代码:

  1. <!-- 通过隐式启动的方式需要在AndroidManifest.xml文件声明-->
  2. <activity
  3. android:permission="com.littlejerk.sample.permission.WEB"
  4. android:name=".other.WebActivity">
  5. <intent-filter>
  6. <action android:name="com.littlejerk.sample.action.VIEW_URL" />
  7. <category android:name="android.intent.category.DEFAULT" />
  8. </intent-filter>
  9. </activity>
复制代码

在activity声明时,activity标签下有一个permission,通过permission就能指定保护该activity的权限名称了,如许 ,只有具有了该权限的activity才能启动它(留意 在定义方和利用 方都要在清单文件中定义和声明自定义的权限),在调用方的清单文件中声明和利用 该权限:

  1. <!--调用方可不用声明-->
  2. <permission
  3. android:label="允许打开WebActivity页面权限"
  4. android:name="com.littlejerk.sample.permission.WEB"
  5. android:protectionLevel="signature" />
  6. <!--调用方必须申请此权限-->
  7. <uses-permission android:name="com.littlejerk.sample.permission.WEB"/>
复制代码

有了权限的控制,activity组件导出的范围就可控了,当我们公司应用间存在相互的组件调用时,就可以利用 同署名 的权限来做限定 ,至于别的 应用由于 不是雷同 的署名 ,以是 它们无法调用我们暴暴露 去的组件,这很有效 地规避了风险。
Activity是我们最常见的一个组件了,但是BroadcastReceiver用的地方也不少,一样平常 安全评测都有提到这个组件的,我们有必要提一提它,着实 各个组件的安全控制也可通过permission来控制的。
BroadcastReceiver的注册有两种方式

  • 静态注册,在Manifest中声明注册
  • 动态注册,在代码中依靠 其他组件,通过registerReceiver注册

BroadcastReceiver有广播的发送方和汲取 方,以是 当利用 permission来校验通讯 的时间 一样平常 都必要 双向校验,即广播的方送方和汲取 方都必要 添加权限检验,保证发送方只将广播发送给信任 的汲取 方,同样的汲取 方也只担当 来自尊 赖方的广播。

广播发送方

发送方必要 在清单文件AndroidManifest.xml中声明权限:

  1. <permission
  2. android:label="声明发送方权限"
  3. android:name="com.littlejerk.sample.permission.BROADCAST_SEND"
  4. android:protectionLevel="signature" />
复制代码

然后利用 sendBroadcast(Intent intent, String receiverPermission)方法发送广播:

  1. //发送广播
  2. Intent intent = new Intent();
  3. intent.setAction("com.littlejerk.sample.broadcast.action.TEST");
  4. sendBroadcast(intent, "com.littlejerk.sample.permission.BROADCAST_SEND");
复制代码

从receiverPermission字面意思就知道,汲取 广播方必须要申请com.littlejerk.sample.permission.BROADCAST_SEND这个自定义权限,不然,无法汲取 到action关照 ,如汲取 方的清单文件AndroidManifest.xml:

  1. <!-- 接收方需申请发送方权限-->
  2. <uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_SEND"/>
复制代码

假如 汲取 方的广播汲取 器不控制本身 的权限,则同开辟 者应用只监听com.littlejerk.sample.broadcast.action.TEST这个action就行了,但是为了双重检验,我们也必要 给汲取 方声明本身 的权限。

广播汲取 方

我们定义一个广播汲取 器TestReceiver:

  1. public class TestReceiver extends BroadcastReceiver {
  2. private static final String TAG = "TestReceiver";
  3. //接收到广播信息的回调
  4. @Override
  5. public void onReceive(Context context, Intent intent) {
  6. //对外来的参数应该做些合法的检查
  7. String action = intent.getAction();
  8. if (TextUtils.isEmpty(action)) {
  9. return;
  10. }
  11. UILog.e(TAG, "action:" + action);
  12. }
  13. }
复制代码

接着在清单文件AndroidManifest.xml中声明控制权限:

  1. <permission
  2. android:label="声明接收方权限"
  3. android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"
  4. android:protectionLevel="signature" />
复制代码

然后把这个控制权限给广播汲取 器,汲取 器有两种注册方式
静态注册方式,在清单文件AndroidManifest.xml中:

  1. <receiver
  2. android:name=".widget.receiver.TestReceiver"
  3. android:permission="com.littlejerk.sample.permission.BROADCAST_RECEIVER">
  4. <intent-filter>
  5. <action android:name="com.littlejerk.sample.broadcast.action.TEST"/>
  6. </intent-filter>
  7. </receiver>
复制代码

然后是动态注册方式,在你必要 注册的地方声明:

  1. Receiver receiver = new Receiver();
  2. IntentFilter intentFilter = new IntentFilter();
  3. intentFilter.addAction("com.littlejerk.sample.broadcast.action.TEST");
  4. registerReceiver(receiver, intentFilter, "com.littlejerk.sample.permission.BROADCAST_RECEIVER", null);
复制代码

这两种注册方式都可以,但是保举 利用 动态注册广播的方式,由于 Android O上为了App性能和功耗的思量 ,对静态注册的广播做了很大的限定 ,至于是什么限定 ,这里就不说了。
我们对汲取 器也做了权限限定 ,那么发送方也必须要申请这个权限才能发送action给它呀,以是 发送方的清单文件AndroidManifest.xml中在原有的基础上必要 添加:

  1. <!-- 发送方需申请接收方权限-->
  2. <uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"/>
复制代码

至此,广播的双向检验就完成了,以上全部 代码都测试过了,没有任何题目 ,很好地过滤了无关广播,保护了组件的安全。

总结

文章重要 讲了四大组件的含义及其告急 性,然后阐明为什么会组件导出及导出风险,有些组件导出时必须的,由于 要实现一些特定功能,但是对于可控的组件,只管 设置不导出。假如 必要 导出组件,我们必要 严酷 地做参数检验,防止崩溃;除此之外,最好地防范就是添加权限,如许 才能有效 地防止被恶意调用,造成不必要的丧失 。

到此这篇关于Android开辟 中关于组件导出的风险及防范的文章就先容 到这了,更多干系 Android 组件导出内容请搜索 脚本之家从前 的文章或继续欣赏 下面的干系 文章渴望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

avatar 或许你会吞 | 2021-9-14 07:33:40 | 显示全部楼层
被admin楼主的逻辑打败了!
回复

使用道具 举报

avatar 此人正在学习 | 2021-9-20 05:38:52 | 显示全部楼层
有节操!
回复

使用道具 举报

avatar 聪聪451 | 2021-9-27 01:46:40 | 显示全部楼层
论坛的人气越来越旺了!
回复

使用道具 举报

avatar 15155324777 | 2021-10-7 14:41:43 | 显示全部楼层
对牛弹琴的人越来越多了!
回复

使用道具 举报

avatar 123456825 | 2021-10-7 17:10:49 | 显示全部楼层
楼上的忘记吃药了!
回复

使用道具 举报

avatar 制菜参力 | 2021-10-8 02:56:16 | 显示全部楼层
这个帖子会火的,鉴定完毕!
回复

使用道具 举报

avatar 123457439 | 2021-10-10 11:27:33 | 显示全部楼层
admin楼主,替我问候您主治大夫!
回复

使用道具 举报

avatar 街角386 | 2021-10-10 11:27:36 | 显示全部楼层
在哪里跌倒,就在那里多爬一会儿!
回复

使用道具 举报

avatar 瑞星卡卡卡卫 | 2021-10-12 13:24:15 | 显示全部楼层
经典!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则