Экспортированный Broadcast Receiver
![]() |
Критичность: ИНФО |
| Способ обнаружения: SAST, APK |
Описание
Broadcast Receiver — это компонент Android-приложения, предназначенный для обработки широковещательных сообщений (broadcasts) от системы или других приложений. Broadcast Receiver позволяет приложениям реагировать на события, происходящие на устройстве, такие как изменение состояния сети, зарядки батареи или получение сообщения. Чтобы Broadcast Receiver был доступен для использования в системе, его необходимо объявить в файле AndroidManifest.xml.
<manifest ... >
<application ... >
<receiver android:name=".ExampleBroadcastReceiver" />
...
</application>
</manifest>
Одним из атрибутов Broadcast Receiver является android:exported, который определяет, может ли Broadcast Receiver принимать сообщения от других приложений. Если значение android:exported равно true, другие приложения могут отправлять сообщения этому Broadcast Receiver через Intent. Если значение false, только компоненты того же приложения могут отправлять сообщения этому Broadcast Receiver.
Логика значения атрибута android:exported по умолчанию менялась со временем и отличалась в зависимости от версий Android. Например, на уровне API 16 (Android 4.1.1) или ниже атрибут android:exported по умолчанию имеет значение true. Если атрибут не задан явно, это может привести к различиям в поведении на устройствах с разными версиями Android. Начиная с версии API 31 (Android 12) стало обязательным явно указывать значение атрибута android:exported. Также важно учитывать, что наличие Intent-фильтров и отсутствие явно заданного значения атрибута android:exported автоматически делает компонент экспортируемым.
Проблема
Если атрибут android:exported для Broadcast Receiver не указан явно, это может привести к непреднамеренному раскрытию внутреннего компонента приложения. В результате злоумышленники могут использовать Broadcast Receiver для отправки сообщений в приложение, что может привести к выполнению нежелательных действий, утечке конфиденциальных данных или даже выполнению кода в контексте уязвимого приложения.
Кроме того, различия в значениях атрибута android:exported по умолчанию на разных версиях Android могут привести к неконсистентному поведению приложения и создать дополнительные точки для атак. Также наличие Intent-фильтров без явного указания android:exported делает Broadcast Receiver экспортируемым по умолчанию, что может привести к несанкционированному доступу.
Рекомендации
-
Всегда явно устанавливайте атрибут
android:exported: Явное указание атрибута исключает неопределенность и четко указывает, должны ли другие приложения иметь доступ к вашему Broadcast Receiver. Пример:В этом примере
android:exported="false"гарантирует, что Broadcast Receiver будет доступен только компонентам того же приложения. -
Ограничьте экспортирование чувствительных Broadcast Receivers: Если Broadcast Receiver предназначен для обработки конфиденциальных данных или функций, которые не должны быть доступны другим приложениям, всегда устанавливайте
android:exported="false". Это предотвращает возможность отправки сообщений этому Broadcast Receiver сторонними приложениями. -
Понимание использования экспортированных Broadcast Receivers: Если требуется, чтобы Broadcast Receiver был доступен другим приложениям, убедитесь, что все входящие Intent проверяются на корректность. Используйте фильтры Intent для ограничения доступа и добавьте проверки данных для предотвращения неправомерного использования.
-
Будьте осторожны с Intent-фильтрами: Наличие Intent-фильтров у Broadcast Receiver без явно установленного
android:exportedделает этот компонент экспортируемым. Поэтому всегда явно указывайтеandroid:exported, если используете Intent-фильтры, чтобы избежать случайного раскрытия компонента. -
Не используйте Broadcast для внутреннего взаимодействия: Если событие нужно передать только внутри одного приложения, не используйте механизм широковещательных сообщений вообще. Класс LocalBroadcastManager объявлен устаревшим (deprecated с 2019 года, версия
androidx.localbroadcastmanager1.1.0) — это была обёртка над глобальной шиной событий приложения, нарушающая принципы разделения ответственности. Вместо него для обмена событиями внутри приложения используйте наблюдаемые источники данных: LiveData или Kotlin Flow (StateFlow/SharedFlow), как правило, через общийViewModel/репозиторий.Пример на Kotlin Flow:
// Источник событий (например, в репозитории или ViewModel) private val _events = MutableSharedFlow<MyEvent>() val events: SharedFlow<MyEvent> = _events.asSharedFlow() suspend fun publish(event: MyEvent) = _events.emit(event)// Подписка (например, в Activity/Fragment) lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.events.collect { event -> handle(event) } } }Такие события остаются в пределах процесса приложения и не могут быть перехвачены или отправлены сторонними приложениями.
-
Для системных Broadcast указывайте флаг экспортируемости при регистрации в рантайме: Если необходимо принимать системные широковещательные сообщения через
Context.registerReceiver(...), начиная с API 33 (Android 13) обязательно указывайте флаг экспортируемости. Для приёма только системных или внутренних сообщений используйтеContext.RECEIVER_NOT_EXPORTED, чтобы получатель не был доступен другим приложениям:ContextCompat.registerReceiver( context, receiver, IntentFilter(Intent.ACTION_BATTERY_LOW), ContextCompat.RECEIVER_NOT_EXPORTED )Флаг
RECEIVER_EXPORTEDследует использовать только тогда, когда получатель действительно должен принимать сообщения от других приложений. -
Проверка манифеста: Регулярно проверяйте файл AndroidManifest.xml на наличие неправильно установленных атрибутов
android:exported, особенно после изменений или обновлений, чтобы убедиться, что видимость компонентов соответствует вашим намерениям.
