Перейти к содержанию

Возможность посылки произвольного широковещательного сообщения через Intent

Критичность: ВЫСОКИЙ
Способ обнаружения: IAST

Описание

Приложение может послать широковещательное сообщение (Broadcast) с помощью Intent. Широковещательные сообщения в Android используются для оповещения других приложений или компонентов о том, что произошло определенное событие. Пример кода для отправки Broadcast с использованием Intent:

Intent intent = new Intent("app.package.SOME_ACTION");
sendBroadcast(intent);

В этом примере создается Intent с определенным действием и отправляется всем приложениям, которые зарегистрированы для обработки данного действия. Проблема возникает, когда данные, используемые для создания Intent, поступают из ненадежных источников.

Проблема

Если данные из сторонних источников (например, из Intent, общедоступных файлов, пользовательского ввода и т.п.) используются для формирования Intent при отправке Broadcast, то появляется возможность отправить произвольное широковещательное сообщение, что может привести к запуску различных компонентов системы или приложений, зарегистрированных на обработку этих сообщений.

Пример кода с уязвимостью:

Intent incomingIntent = getIntent();
String action = incomingIntent.getStringExtra("action");

if (action != null) {
    Intent broadcastIntent = new Intent(action);
    sendBroadcast(broadcastIntent);
}

В этом примере злоумышленник может передать произвольное значение action через Intent, что приведет к отправке широковещательного сообщения, которое может запустить различные компоненты других приложений или системные службы.

Причина проблемы

Проблема заключается в том, что Broadcast, отправленный с использованием Intent, может быть перехвачен другими приложениями или компонентами, если злоумышленник может контролировать содержимое Intent. Это может привести к:

  1. Неожиданному запуску компонентов — Злоумышленник может инициировать запуск определенных компонентов, что может нарушить нормальное функционирование системы или приложений.
  2. Уязвимости безопасности — Отправка неконтролируемого Broadcast может позволить злоумышленнику инициировать события, которые приведут к сбоям или утечке информации.
  3. DoS-атакам — Злоумышленник может посылать частые Broadcast, что создаст нагрузку на систему и вызовет замедление работы устройства.

Рекомендации

  1. Не используйте внешние данные для создания Intent при отправке Broadcast: При формировании Intent для отправки Broadcast избегайте использования данных, полученных из внешних источников. Доверять значениям, переданным через Intent, небезопасно.

  2. Используйте заранее определенные действия: Вместо передачи значений действий (action) из входящих данных, используйте заранее определенные действия, которые безопасны в рамках вашего приложения. Пример безопасного подхода:

    int actionIndex = incomingIntent.getIntExtra("action_index", -1);
    if (actionIndex >= 0) {
        Intent broadcastIntent = new Intent();
        switch (actionIndex) {
            case 0:
                broadcastIntent.setAction("app.package.SOME_SAFE_ACTION");
                break;
            case 1:
                broadcastIntent.setAction("app.package.OTHER_SAFE_ACTION");
                break;
            // Другие варианты действий
        }
        sendBroadcast(broadcastIntent);
    }
    

    В этом примере используется индекс для выбора действия, что предотвращает возможность передачи произвольных значений.

  3. Не используйте Broadcast для внутренних событий: Если событие нужно доставить только внутри вашего приложения, не используйте механизм широковещательных сообщений. Класс LocalBroadcastManager объявлен устаревшим (deprecated с 2019 года) и больше не рекомендуется. Для обмена событиями в пределах процесса используйте наблюдаемые источники данных — LiveData или Kotlin Flow (SharedFlow/StateFlow), обычно через общий ViewModel/репозиторий:

    // Публикация события
    private val _events = MutableSharedFlow<MyEvent>()
    val events: SharedFlow<MyEvent> = _events.asSharedFlow()
    
    suspend fun publish(event: MyEvent) = _events.emit(event)
    

    Такие события остаются в пределах приложения и не могут быть перехвачены или отправлены сторонними приложениями.

    Если же необходимо именно принимать системные широковещательные сообщения через Context.registerReceiver(...), начиная с API 33 (Android 13) указывайте флаг экспортируемости. Для приёма только системных или внутренних сообщений используйте Context.RECEIVER_NOT_EXPORTED, чтобы получатель не был доступен другим приложениям:

    ContextCompat.registerReceiver(
        context,
        receiver,
        IntentFilter(Intent.ACTION_POWER_CONNECTED),
        ContextCompat.RECEIVER_NOT_EXPORTED
    )
    
  4. Проверяйте данные перед использованием: Прежде чем использовать какие-либо данные для формирования Intent, всегда проверяйте их корректность и достоверность. Если возможно, используйте белые списки (whitelist) для разрешенных значений, чтобы предотвратить использование произвольных данных.

Дополнительные примеры

Неправильное использование внешних данных для отправки Broadcast:

public void sendCustomBroadcast(String action) {
    try {
        Intent intent = new Intent(action);
        sendBroadcast(intent);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Без проверки данных action, этот код позволяет злоумышленнику отправить произвольное широковещательное сообщение, что может привести к потенциальной угрозе безопасности.

Ссылки

  1. О Broadcast
  2. Описание Intent
  3. Безопасное использование Broadcast
  4. Регистрация ресивера и флаги экспортируемости (Android 13+)
  5. LiveData
  6. Kotlin Flow в Android
К началу