Reindirizzamento intent

Categoria OWASP: MASVS-PLATFORM: Platform Interaction

Panoramica

Un reindirizzamento di intent si verifica quando un malintenzionato può controllare parzialmente o completamente i contenuti di un intent utilizzato per avviare un nuovo componente nel contesto di un'app vulnerabile.

L'intent utilizzato per avviare il nuovo componente può essere fornito in diversi modi, più comunemente come intent serializzato in un campo extras o sottoposto a marshalling in una stringa e analizzato. Anche il controllo parziale dei parametri può portare allo stesso risultato.

Impatto

L'impatto può variare. Un malintenzionato potrebbe eseguire funzionalità interne nell'app vulnerabile o accedere a componenti privati come oggetti ContentProvider non esportati.

Mitigazioni

In generale, non esporre funzionalità relative al reindirizzamento degli intent nidificati. Nei casi in cui è inevitabile, applica i seguenti metodi di mitigazione:

  • Sanitizza correttamente le informazioni raggruppate. È importante ricordare di controllare o rimuovere i flag (FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION, FLAG_GRANT_PERSISTABLE_URI_PERMISSION, and FLAG_GRANT_PREFIX_URI_PERMISSION) e di verificare dove viene reindirizzato l'intent. IntentSanitizer può aiutarti in questa procedura.
  • Utilizza gli oggetti PendingIntent. Ciò impedisce l'esportazione del componente e rende l'intent di azione di destinazione immutabile.

Le app possono controllare dove viene reindirizzato un intent utilizzando metodi come 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);
}

Le app possono utilizzare IntentSanitizer con una logica simile alla seguente:

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

Protezione predefinita

Android 16 introduce una soluzione di rafforzamento della sicurezza per impostazione predefinita per gli exploit di reindirizzamento Intent. Nella maggior parte dei casi, le app che utilizzano intent normalmente non riscontrano problemi di compatibilità.

Disattivare la gestione del reindirizzamento intent

Android 16 introduce una nuova API che consente alle app di disattivare le protezioni di sicurezza all'avvio. Ciò potrebbe essere necessario in casi specifici in cui il comportamento di sicurezza predefinito interferisce con casi d'uso legittimi dell'app.

In Android 16, puoi disattivare le protezioni di sicurezza utilizzando il metodo removeLaunchSecurityProtection() sull'oggetto Intent. Ad esempio:

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

Errori comuni

  • Controllare se getCallingActivity() restituisce un valore diverso da null. Anche le app dannose possono fornire un valore null per funzione.
  • Supponendo che checkCallingPermission() funzioni in tutti i contesti o che il metodo generi un'eccezione quando restituisce effettivamente un numero intero.

Funzionalità di debug

Per le app che hanno come target Android 12 (livello API 31) o versioni successive, puoi attivare una funzionalità di debug che, in alcuni casi, ti aiuta a rilevare se la tua app esegue un lancio non sicuro di un intent.

Se la tua app esegue entrambe le seguenti azioni, il sistema rileva un avvio di intent non sicuro e si verifica una violazione delle StrictMode:

  • La tua app esegue l'unparceling di un intent nidificato dagli extra di un intent recapitato.
  • La tua app avvia immediatamente un componente dell'app utilizzando questo intent nidificato, ad esempio passando l'intent in startActivity(), startService() o bindService().

Risorse