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

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

Описание

В приложении Intent на запуск другого компонента может быть создан с указанием ComponentName.

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

В этом примере Intent жестко привязан к конкретной Activity, которая указана явно через ComponentName. Это может создать потенциальную уязвимость, если информация о компонентах приходит извне.

Проблема

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

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

Intent incomingIntent = getIntent();
String packageName = incomingIntent.getStringExtra("package");
String activityName = incomingIntent.getStringExtra("activity");

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

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

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

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

Злоумышленники могут использовать такие уязвимости для различных атак:

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

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

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

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

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

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

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

    <activity
        android:name=".SomePrivateActivity"
        android:exported="false" />
    

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

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

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

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

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

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

Ссылки

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