4.2.3 高级话题

4.2.3.1 结合导出属性和意图过滤器设置(用于接收器)

表 4.2-3 展示了实现接收器时,导出设置和意图过滤器元素的允许的组合。 下面介绍为什么原则上禁止使用带有意图过滤器定义的exported ="false"

表 4.2-3 可用与否,导出属性和意图过滤器元素的组合

导出属性的值
True False 未指定
意图过滤器已定义 OK 不使用 不使用
意图过滤器未定义 OK OK 不使用

未指定接收器的导出属性时,接收器是否为公共的,取决于该接收器的意图过滤器的存在与否 [6]。但是,在本手册中,禁止将导出的属性设置为不确定的。 通常,如前所述,最好避免依赖任何给定 API 的默认行为的实现;此外,如果存在明确的方法(如导出属性)来启用重要的安全相关设置,那么使用这些方法总是一个好主意。

[6] 如果意图过滤器已定义,接收器是公共的,否则是私有的。更多信息请参考 https://developer.android.com/guide/topics/manifest/receiver-element.html#exported

即使在相同的应用中将广播发送到私有接收器,其他应用中的公共接收器也可能会意外调用。 这就是为什么禁止指定带有意图过滤器定义的exported ="false"。 以下两张图展示了意外调用的发生情况。

图 4.2-4 是一个正常行为的例子,隐式意图只能在同一个应用中调用私有接收器(应用 A)。 意图过滤器(在图中,action ="X")仅在应用 A 中定义,所以这是预期的行为。

图 4.2-5 是个例子,应用 B 和应用 A 中都定义了意图过滤器(见图中的action ="X")的。首先,当另一个应用(应用 C)通过 隐式意图发送广播,它们不被私有接收器(A-1)接收。 所以不会有任何安全问题。 (请参阅图中的橙色箭头标记。)从安全角度来看,问题是应用 A 对同一应用中的私有接收器的调用。 当应用 A 广播隐式意图时,不仅是相同应用中的私有接收器,而且具有相同意图过滤器定义的公共接收器(B-1)也可以接收意图。 (图中的红色箭头标记)。 在这种情况下,敏感信息可能会从应用 A 发送到 B。当应用 B 是恶意软件时,会导致敏感信息的泄漏。 当发送有序广播时,它可能会收到意外的结果信息。

然而,当广播接收器仅接收由系统发送的广播意图时,应使用带有意图过滤器定义的exported="false"。 其他组合不应使用。 这是基于这样一个事实,即系统发送的广播意图可以通过exported="false"来接收。 如果其他应用发送的意图的ACTION与系统发送的广播意图相同,则可能会通过接收它而导致意外行为。 但是,这可以通过指定exported="false"来防止。

4.2.3.2 接收器在启动应用之前不会被注册

请务必注意,在AndroidManifest.xml中定义的静态广播接收器,在安装后不会自动启用 [7]。应用只有在第一次启动后才能接收广播;因此,安装后无法使用接收的广播作为启动操作的触发器。 但是,如果在发送广播时设置了Intent.FLAG_INCLUDE_STOPPED_PACKAGES标志,则即使是尚未第一次启动的应用也会收到该广播。

[7] 在 3.0 之前的版本中,接收器可以通过安装 App 自动启动。

4.2.3.3 私有广播接收器可以接收由相同 UID 发送的广播

应用

相同的 UID 可以提供给几个应用。 即使它是私有广播接收器,也可以接收从 UID 相同的应用发送的广播。 但是,这不会是一个安全问题。 由于可以确保 UID 相同的应用具有用于签署 APK 的一致的开发人员密钥。 这意味着私有广播接收器收到的广播,只是从内部应用发送的广播。

4.2.3.4 广播的类型和特性

根据是否有序以及是否粘滞的组合,广播有四种类型。 要发送的广播类型基于广播发送方法而确定。 请注意,粘性广播在 Android 5.0(API Level 21)中已弃用。

类型 发送方法 是否有序 是否粘性
普通 sendBroadcast()
有序 sendOrderedBroadcast()
粘性 sendStickyBroadcast()
粘性有序 sendStickyOrderedBroadcast()

每个广播类型的特性描述如下:

类型 特性
普通 普通广播发送到可接收的广播接收器时消失。 广播由多个广播接收器同时接收。 这与有序广播有所不同。 广播被允许由特定的广播接收机接收。
有序 有序广播的特点是,可接收的广播接收器依次接收广播。 优先级较高的广播接收器较早收到。 当广播被传送到所有广播接收器或广播接收器调用abortBroadcast(),广播将消失。 广播被允许由声明了特定权限的广播接收器接收。 另外,广播接收器发送的结果信息,可以由发送者使用有序广播接收。 SMS 接收通知的广播(SMS_RECEIVED)是有序广播的代表性示例。
粘性 粘性广播不会消失并保留在系统中,然后调用registerReceiver()的应用可以稍后接收粘性广播。 由于粘性广播与其他广播不同,它不会自动消失。 因此,当不需要粘性广播时,需要显式调用removeStickyBroadcast()来删除粘滞广播。 此外,带有特定权限的受限的广播接收器无法接收广播。 电池状态变化通知的广播(ACTION_BATTERY_CHANGED)是粘性广播的代表性示例。
粘性有序 这是具有有序和粘性特征的广播。 与粘性广播相同,它不能仅仅允许带有特定权限的广播接收器接收广播。

从广播特性行为的角度来看,上表反过来排列在下面的表中。

广播的特征行为 普通 有序 粘性 粘性有序
由权限限制的广播接收器可以接收广播 OK OK - -
从广播接收器获得过程结果 - OK - OK
使广播接收器按顺序处理广播 - OK - OK
稍后收到已经发送的广播 - - OK OK

4.2.3.5 广播信息可能输出到LogCat

发送/接收的广播基本上不会输出到LogCat。 然而,缺少权限导致接收/发送方的错误时,将输出错误日志。 由广播发送的意图信息包含在错误日志中,因此在发生错误之后,需要注意,发送广播时,意图的信息显示在LogCat中。

发送方的缺少权限的错误:

W/ActivityManager(266): Permission Denial: broadcasting Intent { act=org.jssec.android.broadcastreceive
r.creating.action.MY_ACTION } from org.jssec.android.broadcast.sending (pid=4685, uid=10058) requires o
rg.jssec.android.permission.MY_PERMISSION due to receiver org.jssec.android.broadcastreceiver.creating/
org.jssec.android.broadcastreceiver.creating.CreatingType3Receiver

接收方的缺少权限的错误:

W/ActivityManager(275): Permission Denial: receiving Intent { act=org.jssec.android.broadcastreceiver.c
reating.action.MY_ACTION } to org.jssec.android.broadcastreceiver.creating requires org.jssec.android.p
ermission.MY_PERMISSION due to sender org.jssec.android.broadcast.sending (uid 10158)

4.2.3.6 在主屏幕放置应用的快捷方式时,需要注意的东西

在下面的内容中,我们讨论了创建快捷方式时的一些需要注意的东西,它们用于从主屏幕启动应用,或者用于创建 URL 快捷方式,例如 Web 浏览器中的书签。 作为一个例子,我们考虑如下所示的实现。

在主屏幕放置应用的快捷方式:

Intent targetIntent = new Intent(this, TargetActivity.class);

// Intent to request shortcut creation

Intent intent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
// Specify an Intent to be launched when the shortcut is tapped
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, targetIntent);
Parcelable icon = Intent.ShortcutIconResource.fromContext(context, iconResource);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
intent.putExtra("duplicate", false);

// Use Broadcast to send the system our request for shortcut creation
context.sendBroadcast(intent);

在由上面的代码片段发送的广播中,接收器是主屏幕应用,并且很难识别包名; 我们必须谨慎记住,这是一个向公共接收器传递的隐式意图。 因此,此片段发送的广播,可以被任何任意应用接收,包括恶意软件;因此,在意图中包含敏感信息可能会造成信息泄漏的风险。 特别重要的是要注意,在创建基于 URL 的快捷方式时,秘密信息可能包含在 URL 本身中。

作为对策,有必要遵循“4.2.1.2 公共广播接收器 - 接收/发送广播”中列出的要点,并确保传输的意图不包含敏感信息。


书籍推荐