粘性广播
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
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
,该方法可实现观察者模式。
如需详细了解如何确保广播的安全,请参阅广播概览页面。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2023-12-13。
[null,null,["最后更新时间 (UTC):2023-12-13。"],[],[],null,["# Sticky Broadcasts\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-PLATFORM: Platform Interaction](https://mas.owasp.org/MASVS/09-MASVS-PLATFORM)\n\nOverview\n--------\n\nAndroid apps and the Android system can use broadcasts as a messaging system to notify other apps of events that they might be interested in. *Sticky broadcasts* are a special type of broadcast for which the sent intent object(s) remains in the cache after the broadcast is complete. The system may re-broadcast sticky intents to later registrations of receivers. Unfortunately, the sticky broadcasts API suffers from a number of security-related shortcomings, which is why it was deprecated in Android 5.0 (API level 21).\n\n### Anyone can access sticky broadcasts\n\nSticky broadcasts cannot be restricted to receivers that hold certain permissions. Therefore, they aren't suitable for broadcasting sensitive information. It might be tempting to think that specifying the [application package name](/reference/android/content/Intent#setPackage(java.lang.String)) on the broadcast `Intent` limits the set of `BroadcastReceivers`: \n\n### Kotlin\n\n val intent = Intent(\"com.example.NOTIFY\").apply {\n setPackage(\"com.example.myapp\")\n }\n applicationContext.sendBroadcast(intent)\n\n### Java\n\n Intent intent = new Intent(\"com.example.NOTIFY\");\n intent.setPackage(\"com.example.myapp\");\n getApplicationContext().sendBroadcast(intent);\n\nIn the example, only receivers in the `com.example.myapp` package receive the intent when the broadcast is sent. However, the package name filter isn't applied when the Intent is re-broadcast from the sticky cache. When registering a receiver using the [`registerReceiver()`](/reference/android/content/Context#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter)) method, all intents in the sticky cache that match the specified filter are re-broadcast to the receiver regardless of the package name in which the receiver resides.\n\n### Anyone can send sticky broadcasts\n\nTo send sticky broadcasts, an app only requires the `android.permission.BROADCAST_STICKY` permission, which is granted automatically when the app is installed. Therefore, attackers can send any intent to any receiver, potentially gaining unauthorized access to another app. Broadcast receivers can restrict the senders to those holding a certain permission. However, by doing so, the receiver can't receive broadcasts from the sticky cache because those are not sent in the context of any app's identity and aren't broadcast with any permissions.\n\n### Anyone can modify sticky broadcasts\n\nWhen an intent is part of a sticky broadcast, that intent replaces any previous instance that has the same action, data, type, identifier, class, and categories in the sticky cache. Therefore, an attacker can trivially overwrite the extra data in a sticky intent from a legitimate app, which might then get re-broadcast to other receivers.\n\nBroadcasts sent using the [`sendStickyOrderedBroadcast()`](/reference/android/content/Context#sendStickyOrderedBroadcast(android.content.Intent,%20android.content.BroadcastReceiver,%20android.os.Handler,%20int,%20java.lang.String,%20android.os.Bundle)) method are delivered to one receiver at a time to allow receivers with higher priority to consume the broadcast before it's delivered to receivers with lower priority. As each receiver executes in turn, it can propagate a result to the next receiver, such as by calling [`setResultData()`](/reference/android/content/BroadcastReceiver#setResultData(java.lang.String)), or it can [abort the broadcast](/reference/android/content/BroadcastReceiver#abortBroadcast()), preventing subsequent receivers from receiving the broadcast. An attacker that can receive sticky ordered broadcasts from a legitimate app can create a high-priority receiver to tamper with the broadcast result data or drop broadcasts completely.\n\nImpact\n------\n\nImpact varies depending on how sticky broadcasts are used and what data is passed to the broadcast receivers. Generally speaking, use of sticky broadcasts can lead to sensitive data exposure, data tampering, unauthorized access to execute behavior in another app, and denial of service.\n\nMitigations\n-----------\n\nSticky broadcasts shouldn't be used. The recommended pattern is to use non-sticky broadcasts with another mechanism, such as a local database, to retrieve the current value whenever desired.\n\nDevelopers can control who can receive non-sticky broadcasts using [permissions](/guide/components/broadcasts#restrict-broadcasts-permissions) or by setting the [application package name](/reference/android/content/Intent#setPackage(java.lang.String)) on the intent. Furthermore, if a broadcast doesn't need to be sent to components outside of an app, use [`LiveData`](/reference/androidx/lifecycle/LiveData), which implements the [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern).\n\nMore information about securing broadcasts can be found on the [broadcasts overview](/guide/components/broadcasts#security-and-best-practices) page."]]