粘性广播

OWASP 类别MASVS-PLATFORM:平台互动

概览

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 内的 extra 数据,而后可能会向其他接收器重新发送广播。

sendStickyOrderedBroadcast() 方法一次向一个接收器发送广播,以便让优先级较高的接收器先收到广播,然后再发送给优先级较低的接收器。当接收器逐个顺序执行时,接收器可以向下传递结果(例如通过调用 setResultData()),也可以中止广播,阻止后续接收器接收广播。如果攻击者可以从合法应用接收排序后的粘性广播,则可能会创建高优先级接收器来篡改广播结果数据,或完全丢弃广播。

影响

具体影响取决于粘性广播的使用方式以及传递给广播接收器的数据。一般来说,使用粘性广播可能会导致敏感数据泄露、数据遭到篡改、未经授权的访问以执行另一个应用的行为,以及拒绝服务攻击。

缓解措施

请勿使用粘性广播。推荐的模式是将非粘性广播与其他机制(例如本地数据库)搭配使用,以便根据需要检索当前值。

开发者可以使用权限或通过在 intent 上设置应用软件包名称来控制谁能接收非粘性广播。此外,如果您不需要向应用以外的组件发送广播,则可以使用 LiveData,该方法可实现观察者模式

如需详细了解如何确保广播的安全,请参阅广播概览页面。