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

Возможность запуска произвольного Service через Intent

Описание

Приложение может создать Intent для запуска другого компонента, такого как Service, с использованием ComponentName.

Intent intent = new Intent();
intent.setComponent(
    new ComponentName("app.package", "app.package.SomeService")
);
startService(intent);

В этом примере Intent напрямую указывает на определенный Service с помощью ComponentName. Такая конструкция становится опасной, если информация о сервисе поступает из внешних источников.

Проблема

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

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

Intent incomingIntent = getIntent();
String packageName = incomingIntent.getStringExtra("package");
String serviceName = incomingIntent.getStringExtra("service");

if (packageName != null && serviceName != null) {
    Intent intent = new Intent();
    intent.setComponent(new ComponentName(packageName, serviceName));
    startService(intent);
}

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

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

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

  1. Запуску приватных сервисов — Злоумышленник может запустить Service, который предназначен для использования только внутри приложения.
  2. Неожиданные последствия — Запуск сервиса в неправильное время или с некорректными данными может привести к сбоям или изменению работы приложения.
  3. Повышенная нагрузка — Частый запуск ресурсоемких сервисов может создавать нагрузку на систему, что ухудшает производительность устройства и работу приложения.

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

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

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

    int actionIndex = incomingIntent.getIntExtra("action_index", -1);
    if (actionIndex >= 0) {
        Intent intent = new Intent();
        switch (actionIndex) {
            case 0:
                intent.setClass(this, SyncService.class);
                break;
            case 1:
                intent.setClass(this, UploadService.class);
                break;
            // Другие варианты действий
        }
        startService(intent);
    }
    

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

  3. Используйте Intent-фильтры и разрешения: Убедитесь, что приватные Service не могут быть запущены внешними приложениями. Это можно сделать, ограничив экспортирование компонентов с помощью android:exported="false" в AndroidManifest.xml. Например:

    <service
        android:name=".SomePrivateService"
        android:exported="false" />
    

    Установка android:exported="false" гарантирует, что данный Service не может быть запущен другими приложениями через Intent.

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

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

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

public void startComponent(String packageName, String serviceName) {
    try {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(packageName, serviceName));
        startService(intent);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Без проверки данных packageName и serviceName, этот код позволяет злоумышленнику указывать любые сервисы для запуска.

Ссылки

  1. О Service
  2. Описание Intent
  3. Безопасное использование Intent
  4. Защита компонентов приложения
  5. Android Security Checklist
К началу