四大组件安全

本文为学习记录,将一些重点记录下。参考droidsec网站。推荐大家关注一下。
每个Application由Activity、Service、content Provider和Broadcast Receiver等基本组件组成。

Activtity

包括显示启动和隐式启动,activity都必须在配置文件中注册组件。私有activity推荐显示启动,隐式启动需要在配置文件中添加intent-filter的action属性。

Activity的四种加载模式launch mode

standard:默认的启动模式,每次启动都会创建该活动的一个新的实例放入栈顶。
singleTop:启动活动时如果发现返回栈的栈顶已经是该活动,则直接使用,不再创建新实例。
singleTask:启动活动时如果发现返回栈中存在该活动,则直接使用,并把其上面的活动出栈。
singleInstance:该模式下会有单独的栈来管理该活动,解决不同程序访问的共享活动实例问题。
可在activity元素中配置android:launchMode属性。
taskAffinity:android中task管理activity,task的命令取决于affinity。默认情况下一个app下所有activity属于同一task,可以在配置文件中设置affinity的值来改变task的分配。
FLAG_ACTIVITY_NEW_TASK:启动activity时通过setFlags()或addFlags()方法设置intent的flags属性也能够改变launch mode。
FLAG_ACTIVITY_NEW_TASK标记代表创建新的task,判断其taskAffinity值。(被启动的Activity既不在前台也不在后台)。
FLAG_ACTIVITY_MULTIPLE_TASK标记能和FLAG_ACTIVITY_NEW_TASK同时设置。这种情况下必会创建的task,所以intent中不应携带敏感数据。

外部应用启动

android:exported:该属性为true时可被外部应用启动。false只能被自身app或者同user id或root启动。
android:protectionLevel:exported属性只是用于限制Activity是否暴露给其他app,通过配置文件中的权限申明也可以限制外部启动activity。
normal:默认值,低风险,无需用户确认。
dangerous:会警示用户。
signature:仅授予那些和本程序应用了相同密钥来签名的程序。
signatureOrSystem:类似signature,同时系统程序也有资格访问。

安全建议

  • app内使用的私有Activity不应配置intent-filter,如果配置了intent-filter需设置exported属性为false。
  • 使用默认taskAffinity
  • 使用默认launchMode
  • 启动Activity时不设置intent的FLAG_ACTIVITY_NEW_TASK标签
  • 谨慎处理接收的intent以及其携带的信息
  • 签名验证内部(in-house)app
  • 当Activity返回数据时候需注意目标Activity是否有泄露信息的风险
  • 目的Activity十分明确时使用显示启动
  • 谨慎处理Activity返回的数据,目的Activity返回的数据有可能是恶意应用伪造的
  • 验证目标Activity是否恶意app,以免受到intent欺骗,可用hash签名验证
  • When Providing an Asset Secondhand, the Asset should be Protected with the Same Level of Protection
  • 尽可能的不发送敏感信息,应考虑到启动public Activity中intent的信息均有可能被恶意应用窃取的风险

Broadcast Recevier

Broadcast Recevier 广播接收器继承自BroadcastReceiver基类,可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。
广播接收器既可以在manifest文件中声明,也可以在代码中进行动态的创建,并以调用Context.registerReceiver()的方式注册至系统。
广播接收器仅在执行onReceive()方法时处于活跃状态,当onReceive()返回后,它为失活状态。仅仅拥有失活状态组件在其他进程需要内存时随时会被杀掉,因此,我们让onReceive()启动一个新服务,并用其完成任务,于是系统就知道进程仍然在处理工作,就可以避免被判定为失活状态。

权限

Intent setPackage:设置接收app
abstract void sendBroadcast(Intent intent, String reveiverPermission):设置接收权限
protectionLevel属性类似于activity

广播类型

系统广播
自定义广播

Ordered Broadcast

有序广播和无序广播

sticky broadcast

粘性广播,发送给对应的reveiver后保存在AMS中,当有新的动态注册的reveiver请求AMS注册时,如果有接收该广播的权限,那么这个广播会被发送到该reveiver。
sendStickBroadcast()是发送粘性广播的api,需要权限android.Manifest.permission.BROADCAST_STICKY

变动

android3.1以及之后版本广播接收器不能在启动应用前注册。可以通过设置intent的flag为Intent.FLAG_INCLUDE_STOPPED_PACKAGES将广播发送给未启动应用的广播接收器。

分类

  1. 私有广播接收器:只接收app自身发出的广播
  2. 公共广播接收器:能接收所有app发出的广播
  3. 内部广播接收器:只接收内部app发出的广播

建议:

私有广播接收器设置exported=false,不配置intent-filter。(私有广播接收器依然能接收到同UID的广播)
内部app之间的广播使用protectionLevel=’signature’验证其是否真是内部app
sticky broadcast粘性广播中不应包含敏感信息
Ordered Broadcast建议设置接收权限receiverPermission,避免恶意应用设置高优先级抢收此广播后并执行abortBroadcast()方法。

Content Provider

Content URIs

Content URI中包含了整个provider的以符号表示的名字(它的authority) 和指向一个表的名字(一个路径)。
content://com.example.app.provider/table1/1
A. 标准前缀表明这个数据被一个内容提供器所控制。
B. URI的权限部分;它标识这个内容提供器。对于第三方应用程序,这应该是一个全称类名(小写)以确保唯一性。权限 元素的权限属性中进行声明:
  1. <provider  
  2. android:name="com.example.databasetest.DatabaseProvider"  
  3. android:authorities="com.example.databasetest.provider" >  
  4. </provider>
使用的时候输入对应的URL权限即可。
C. 用来判断请求数据类型的路径。这可以是0或多个段长。如果内容提供器只暴露了一种数据类型(比如,只有火车),这个分段可以没有。如果提供器暴露若干类型,包括子类型,那它可以是多个分段长-例如,提供”land/bus”, “land/train”, “sea/ship”, 和”sea/submarine”这4个可能的值。
D. 被请求的特定记录的ID,如果有的话。这是被请求记录的_ID数值。如果这个请求不局限于单个记录, 这个分段和尾部的斜线会被忽略。

权限

申请读取短信的权限
<uses-permission android:name="android.permission.READ_SMS"></uses-permission>
自定义权限


变动

Contentprovider组件在 API-17(android4.2)及以上版本由以前的exported属性默认ture改为默认false。
Contentprovider无法在android2.2( API-8)申明为私有。

安全建议

  1. minSdkVersion不低于9
  2. 不向外部app提供的数据的私有content provider设置exported=“false”避免组件暴露(编译api小于17时更应注意此点)
  3. 使用参数化查询避免注入
  4. 内部app通过content provid交换数据设置protectionLevel=“signature”验证签名
  5. 公开的content provider确保不存储敏感数据
  6. Uri.decode() before use ContentProvider.openFile()
  7. 提供asset文件时注意权限保护
解决方法Uri.decode()

Android Service Security

常见方法

调用stopService则会造成Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在Activity结束之后(onDestroy)自动结束。
OnCreate() 系统在service第一次创建时执行
OnDestroy() 系统在service不再被使用并要销毁时调用此方法,这是service收到的最后一个调用.
bindService来绑定服务.
onHandleIntent调用工作线程处理请求.
IntentService这是一个Service的子类,使用一个工作线程来处理所有的启动请求,一次处理一个.这是你不需你的service同时处理多个请求时的最好选择.你所有要做的就是实现onHandleIntent(),这个方法接收每次启动请求发来的intent.

注意

如果你打算只在本应用内使用自己的service,那么你不需指定任何intent过滤器.不使用intent过滤器,你必须使用一个明确指定service的类名的intent来启动你的service.
另外,你也可以通过包含android:exported属性,并指定其值为“false”来保证你的service是私有的.即使你的service使用了intent过滤器,也会起作用。

安全建议

  • exported属性明确定义
  • 私有service不定义intent-filter并且设置exported为false
  • 公开的service设置exported为true,intent-filter可以定义或者不定义
  • 内部/合作service设置exported为true,intent-filter不定义
  • 只被应用本身使用的service应设置为私有
  • service接收到的数据需需谨慎处理
  • 内部service需使用签名级别的protectionLevel来判断是否未内部应用调用
  • 不应在service创建(onCreate方法被调用)的时候决定是否提供服务,应在onStartCommand/onBind/onHandleIntent等方法被调用的时候做判断.
  • 当service又返回数据的时候,因判断数据接收app是否又信息泄露的风险
  • 有明确的服务需调用时使用显示意图
  • 尽量不发送敏感信息
  • 合作service需对合作公司的app签名做效验

案例

隐式启动services,当存在同名services,先安装应用的services优先级高

猜你喜欢

转载自blog.csdn.net/u012195899/article/details/53410759