Перенаправление намерения

Категория OWASP: MASVS-PLATFORM: взаимодействие с платформой

Обзор

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

Намерение, используемое для запуска нового компонента, можно указать несколькими способами. Чаще всего оно передается в виде сериализованного намерения в поле extras или преобразуется в строку и анализируется. Частичное управление параметрами также может привести к такому результату.

Влияние

Влияние может быть разным. Злоумышленник может выполнить внутренние функции уязвимого приложения или получить доступ к закрытым компонентам, например к неэкспортированным объектам ContentProvider.

Предотвращение атак

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

  • Правильно очищайте информацию, входящую в пакет. Важно помнить, что нужно проверять или удалять флаги (FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION, FLAG_GRANT_PERSISTABLE_URI_PERMISSION, and FLAG_GRANT_PREFIX_URI_PERMISSION) и проверять, куда перенаправляется намерение. IntentSanitizer.
  • Используйте объекты PendingIntent. Это предотвращает экспорт компонента и делает намерение целевого действия неизменяемым.

Приложения могут проверять, куда перенаправляется намерение, с помощью таких методов, как ResolveActivity:

Kotlin

val intent = getIntent()
// Get the component name of the nested intent.
val forward = intent.getParcelableExtra<Parcelable>("key") as Intent
val name: ComponentName = forward.resolveActivity(packageManager)
// Check that the package name and class name contain the expected values.
if (name.packagename == "safe_package" && name.className == "safe_class") {
    // Redirect the nested intent.
    startActivity(forward)
}

Java

Intent intent = getIntent()
// Get the component name of the nested intent.
Intent forward = (Intent) intent.getParcelableExtra("key");
ComponentName name = forward.resolveActivity(getPackageManager());
// Check that the package name and class name contain the expected values.
if (name.getPackageName().equals("safe_package") &&
        name.getClassName().equals("safe_class")) {
    // Redirect the nested intent.
    startActivity(forward);
}

Приложения могут использовать IntentSanitizer, применяя логику, похожую на следующую:

Kotlin

val intent = IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent)

Java

Intent intent = new  IntentSanitizer.Builder()
     .allowComponent("com.example.ActivityA")
     .allowData("com.example")
     .allowType("text/plain")
     .build()
     .sanitizeByThrowing(intent);

Стандартный уровень защиты

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

Как отключить обработку перенаправления намерений

В Android 16 появился новый API, который позволяет приложениям отказаться от защиты при запуске. Это может потребоваться в случаях, когда настройки безопасности по умолчанию мешают использовать приложение по назначению.

В Android 16 можно отключить защиту с помощью метода removeLaunchSecurityProtection() для объекта Intent. Пример:

val i = intent
val iSublevel: Intent? = i.getParcelableExtra("sub_intent")
iSublevel?.removeLaunchSecurityProtection() // Opt out from hardening
iSublevel?.let { startActivity(it) }

Распространенные ошибки

  • Проверка, возвращает ли функция getCallingActivity() ненулевое значение. Вредоносные приложения могут передавать для этой функции нулевое значение.
  • Предположим, что checkCallingPermission() работает во всех контекстах или что метод вызывает исключение, когда на самом деле возвращает целое число.

Функции отладки

Если ваше приложение предназначено для Android 12 (уровень API 31) или более поздней версии, вы можете включить функцию отладки, которая в некоторых случаях помогает определить, безопасно ли приложение запускает намерение.

Если ваше приложение выполняет оба следующих действия, система обнаруживает небезопасный запуск намерения и происходит нарушение StrictMode.

  • Ваше приложение извлекает вложенное намерение из дополнительных данных доставленного намерения.
  • Ваше приложение сразу запускает компонент приложения, используя вложенное намерение, например передавая намерение в startActivity(), startService() или bindService().

Ресурсы