固定式廣播訊息
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
OWASP 類別:MASVS-PLATFORM:平台互動
總覽
Android 應用程式和 Android 系統可以使用廣播訊息做為傳訊系統,如果其他應用程式有可能感興趣的事件,就會收到該系統的通知。「固定式廣播訊息」是一種特殊的廣播訊息,系統會在訊息播送完成後,將已傳送的意圖物件保留在快取中。此外,系統可能會將固定式意圖重新播送給日後註冊的接收器。遺憾的是,固定式廣播訊息 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,系統就不會套用套件名稱篩選器。而當您使用 registerReceiver()
方法註冊接收器時,無論接收器所在套件的名稱為何,系統都會重新將固定式快取中符合指定篩選器的所有意圖播送給接收器。
任何人皆可傳送固定式廣播訊息
如要傳送固定式廣播訊息,應用程式只須具備 android.permission.BROADCAST_STICKY
權限即可,系統會在安裝應用程式時自動授予這項權限。因此,攻擊者可以傳送任何意圖給任何接收器,這樣即使未經授權,他們也可能存取其他應用程式的。廣播接收器則可將傳送者限定為擁有特定權限的傳送者。不過這麼一來,該接收器就無法接收來自固定式快取的廣播訊息,因為這類訊息不會在任何應用程式的識別環境中傳送,也不會使用任何權限播送。
任何人皆可修改固定式廣播訊息
當固定式廣播訊息內含意圖時,該意圖會取代先前在固定式快取中具有相同動作、資料、類型、ID、類別和分類的所有例項。因此,攻擊者可以透過合法的應用程式,輕易覆寫固定式意圖內的額外資料,而這些資料可能會重新播送至其他接收器。
使用 sendStickyOrderedBroadcast()
方法傳送的廣播訊息一次會傳送給一個接收器,讓優先順序較高的接收器先行使用廣播訊息,然後再傳送給優先順序較低的接收器。由於每個接收器會按順序執行,因此可將結果傳播至下一個接收器 (例如透過呼叫 setResultData()
),也可以取消播送,防止後續的接收器接收廣播訊息。如果攻擊者能透過合法應用程式接收排定順序的固定式廣播訊息,可能會建立高優先順序的接收器,藉此竄改廣播訊息的結果資料或完全停止播送。
影響
影響有很多種,具體取決於固定式廣播訊息的使用方式,以及要將哪些資料傳遞給廣播接收器。一般來說,使用固定式廣播訊息可能導致機密資料外洩、資料遭竄改、在未經授權情況下執行其他應用程式的行為,以及阻斷服務攻擊。
因應措施
請勿使用固定式廣播訊息。建議您搭配本機資料庫等其他機制使用非固定式廣播訊息,視需要擷取目前的值。
開發人員可以透過權限,或是在意圖上設定應用程式套件名稱,控制哪些人可以接收非固定式廣播訊息。此外,如果不需要將廣播訊息傳送給應用程式以外的元件,請使用會執行觀測器模式的 LiveData
。
如要進一步瞭解如何保護廣播訊息,請參閱「廣播總覽」頁面。
這個頁面中的內容和程式碼範例均受《內容授權》中的授權所規範。Java 與 OpenJDK 是 Oracle 和/或其關係企業的商標或註冊商標。
上次更新時間:2024-01-05 (世界標準時間)。
[null,null,["上次更新時間:2024-01-05 (世界標準時間)。"],[],[],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."]]