粘性广播

OWASP 类别: MASVS-PLATFORM: Platform Interaction

概览

Android 应用和 Android 系统可以使用广播作为消息传递系统,以通知其他应用它们可能感兴趣的事件。粘性广播是一种特殊的广播类型,其发送的 Intent 对象在广播完成后仍保留在缓存中。系统可以将粘性 Intent 重新广播给稍后注册的接收器。不幸的是,粘性广播 API 存在许多与安全相关的缺点,因此已在 Android 5.0(API 级别 21)中被弃用。

任何人都可以访问粘性广播

粘性广播无法限制为持有特定权限的接收器。因此,它们不适合广播敏感信息。你可能会认为在广播 Intent 上指定应用包名可以限制 BroadcastReceivers 的集合

Kotlin

val intent = Intent("com.example.NOTIFY").apply {
    setPackage("com.example.myapp")
}
applicationContext.sendBroadcast(intent)

Java

Intent intent = new Intent("com.example.NOTIFY");
intent.setPackage("com.example.myapp");
getApplicationContext().sendBroadcast(intent);

在该示例中,只有 com.example.myapp 包中的接收器才能在广播发送时接收 Intent。但是,当 Intent 从粘性缓存重新广播时,包名过滤器不适用。使用 registerReceiver() 方法注册接收器时,无论接收器位于哪个包名中,粘性缓存中所有匹配指定过滤器的 Intent 都会重新广播给该接收器。

任何人都可以发送粘性广播

要发送粘性广播,应用仅需要 android.permission.BROADCAST_STICKY 权限,该权限在应用安装时自动授予。因此,攻击者可以将任何 Intent 发送到任何接收器,从而可能获得对另一个应用的未授权访问。广播接收器可以将发送方限制为持有特定权限的发送方。但是,这样做的话,接收器将无法接收来自粘性缓存的广播,因为这些广播不是在任何应用的身份上下文中发送的,并且不附带任何权限进行广播。

任何人都可以修改粘性广播

当 Intent 是粘性广播的一部分时,该 Intent 将替换粘性缓存中具有相同操作、数据、类型、标识符、类和类别的任何先前实例。因此,攻击者可以轻易地覆盖合法应用中粘性 Intent 的额外数据,这些数据随后可能会被重新广播给其他接收器。

使用 sendStickyOrderedBroadcast() 方法发送的广播会一次只发送给一个接收器,以便较高优先级的接收器可以在广播传递给较低优先级的接收器之前使用该广播。当每个接收器依次执行时,它可以将结果传播给下一个接收器,例如通过调用 setResultData(),或者它可以中止广播,阻止后续的接收器接收该广播。能够接收合法应用发送的粘性有序广播的攻击者可以创建一个高优先级的接收器来篡改广播结果数据或完全丢弃广播。

影响

影响因粘性广播的使用方式以及传递给广播接收器的数据而异。一般来说,使用粘性广播可能导致敏感数据泄露、数据篡改、未经授权访问执行其他应用中的行为以及拒绝服务。

缓解措施

不应使用粘性广播。推荐的模式是使用非粘性广播并结合其他机制(例如本地数据库),以便在需要时检索当前值。

开发者可以使用权限或通过在 Intent 上设置应用包名来控制谁可以接收非粘性广播。此外,如果广播不需要发送到应用之外的组件,请使用 LiveData,它实现了观察者模式

有关保护广播的更多信息,请参见广播概览页面。