Возможность запуска произвольной 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 или даже компонентов других приложений.
Злоумышленники могут использовать такие уязвимости для различных атак:
- Приватные Activities — Злоумышленник может запустить Activity, которая была скрыта от пользователей и может содержать функции, которые не должны быть доступны напрямую.
- Доступ к чувствительной информации — Приватная Activity может отображать или обрабатывать конфиденциальную информацию, которую злоумышленник сможет просмотреть.
- Неожиданное поведение — Запуск компонентов в неожиданном порядке может вызвать некорректное поведение приложения, которое нарушит его безопасность или стабильность.
Рекомендации
-
Не используйте внешние данные для создания ComponentName: При формировании Intent следует избегать использования данных, которые получены из внешних источников. Не стоит доверять значениям, которые пришли через Intent или другим входным данным.
-
Использование безопасных механизмов для выбора компонентов: Вместо того, чтобы передавать имена пакетов или компонентов, используйте "индексы" или другие маркеры, которые будут интерпретированы только в рамках вашего приложения. Пример безопасного подхода:
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 запустить, что исключает возможность прямого указания произвольного компонента.
-
Используйте Intent-фильтры и разрешения: Убедитесь, что приватные Activity не могут быть запущены внешними приложениями. Это можно сделать, ограничив экспортирование компонентов с помощью
android:exported="false"
в AndroidManifest.xml. Например:Установка
android:exported="false"
гарантирует, что данная Activity не может быть запущена другими приложениями через Intent. -
Проверяйте данные перед использованием: Прежде чем использовать какие-либо данные для формирования 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, этот код позволяет злоумышленнику указывать любые классы для запуска.