Przekierowanie intencji

Kategoria OWASP: MASVS-PLATFORM: Platform Interaction

Przegląd

Przekierowanie intencji występuje, gdy osoba przeprowadzająca atak może częściowo lub w pełni kontrolować zawartość intencji używanej do uruchamiania nowego komponentu w kontekście podatnej na ataki aplikacji.

Intencję używaną do uruchamiania nowego komponentu można podać na kilka sposobów, najczęściej jako zserializowaną intencję w polu extras lub przekształconą w ciąg znaków i przeanalizowaną. Częściowa kontrola parametrów może również prowadzić do tego samego wyniku.

Wpływ

Wpływ może być różny. Osoba atakująca może uruchamiać wewnętrzne funkcje podatnej na ataki aplikacji lub uzyskiwać dostęp do prywatnych komponentów, takich jak nieeksportowane obiekty ContentProvider.

Środki ograniczające ryzyko

Ogólnie nie udostępniaj funkcji związanych z przekierowywaniem zagnieżdżonych intencji. W przypadkach, w których jest to nieuniknione, zastosuj te metody ograniczania ryzyka:

  • Odpowiednio oczyść powiązane informacje. Pamiętaj, aby sprawdzać lub usuwać flagi (FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION, FLAG_GRANT_PERSISTABLE_URI_PERMISSION, and FLAG_GRANT_PREFIX_URI_PERMISSION) oraz sprawdzać, dokąd jest przekierowywany zamiar. W tym procesie może Ci pomóc zespół IntentSanitizer.
  • Używaj obiektów PendingIntent. Zapobiega to eksportowaniu komponentu i sprawia, że intencja działania docelowego jest niezmienna.

Aplikacje mogą sprawdzać, dokąd jest przekierowywana intencja, korzystając z takich metod jak 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);
}

Aplikacje mogą używać IntentSanitizer, stosując logikę podobną do tej:

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);

Domyślna ochrona

Android 16 wprowadza domyślne rozwiązanie wzmacniania zabezpieczeń, które chroni przed wykorzystywaniem luk w zabezpieczeniach związanych z przekierowaniem Intent. W większości przypadków aplikacje, które używają intencji, nie będą miały problemów z kompatybilnością.

Rezygnacja z obsługi przekierowania intencji

Android 16 wprowadza nowy interfejs API, który umożliwia aplikacjom rezygnację z ochrony przed uruchomieniem. Może to być konieczne w określonych przypadkach, gdy domyślne zachowanie związane z bezpieczeństwem zakłóca prawidłowe działanie aplikacji.

W Androidzie 16 możesz zrezygnować z ochrony, używając metody removeLaunchSecurityProtection() na obiekcie Intent. Przykład:

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

Typowe błędy

  • Sprawdzenie, czy funkcja getCallingActivity() zwraca niepustą wartość. Szkodliwe aplikacje mogą dostarczyć pustą wartość dla tej funkcji.
  • Zakładamy, że checkCallingPermission() działa we wszystkich kontekstach lub że metoda zgłasza wyjątek, gdy w rzeczywistości zwraca liczbę całkowitą.

Funkcje debugowania

W przypadku aplikacji kierowanych na Androida 12 (poziom API 31) lub nowszego możesz włączyć funkcję debugowania, która w niektórych przypadkach pomaga wykryć, czy aplikacja wykonuje niebezpieczne uruchomienie intencji.

Jeśli Twoja aplikacja wykonuje oba te działania, system wykryje niebezpieczne uruchomienie intencji i nastąpi StrictMode naruszenie zasad:

  • Aplikacja rozpakowuje zagnieżdżoną intencję z dodatków dostarczonej intencji.
  • Aplikacja natychmiast uruchamia komponent aplikacji za pomocą tej zagnieżdżonej intencji, np. przekazując intencję do startActivity(), startService() lub bindService().

Zasoby