Intents pendientes

Categoría de OWASP: MASVS-PLATFORM: Interacción con la plataforma

Descripción general

Un PendingIntent es una referencia a un token que mantiene el sistema. La aplicación A puede pasar un PendingIntent a la aplicación B para permitir que la aplicación B ejecute acciones predefinidas en nombre de la aplicación A, independientemente de si esta sigue activa.

Riesgo: Intents pendientes mutables

Un PendingIntent puede ser mutable, lo que significa que la aplicación B puede actualizar el intent interno que especifica la acción según la lógica que se describe en la documentación de fillIn(). En otras palabras, una app maliciosa puede modificar los campos sin completar de un PendingIntent y permitir el acceso a los componentes de la aplicación vulnerable que no se exportaron.

Impacto

El impacto de esta vulnerabilidad varía según la implementación de la funcionalidad no exportada de destino de la app.

Mitigaciones

General

Asegúrate de que la acción, el componente y el paquete estén configurados para evitar las vulnerabilidades más graves:

Kotlin

val intent = Intent(intentAction)

// Or other component setting APIs e.g. setComponent, setClass
intent.setClassName(packageName, className)

PendingIntent pendingIntent =
    PendingIntent.getActivity(
        context,
        /* requestCode = */ 0,
        intent, /* flags = */ PendingIntent.FLAG_IMMUTABLE
    )

Java

Intent intent = new Intent(intentAction);

// Or other component setting APIs e.g. setComponent, setClass
intent.setClassName(packageName, className);

PendingIntent pendingIntent =
        PendingIntent.getActivity(
            getContext(),
            /* requestCode= */ 0,
            intent, /* flags= */ 0);

Marca IMMUTABLE

Si tu app se orienta a Android 6 (nivel de API 23) o versiones posteriores, especifica la mutabilidad. Por ejemplo, esto se puede hacer usando FLAG_IMMUTABLE para evitar que una aplicación maliciosa complete los campos vacíos:

Kotlin

val pendingIntent =
    PendingIntent.getActivity(
        context,
        /* requestCode = */ 0,
        Intent(intentAction),
        PendingIntent.FLAG_IMMUTABLE)

Java

PendingIntent pendingIntent =
        PendingIntent.getActivity(
            getContext(),
            /* requestCode= */ 0,
            new Intent(intentAction),
            PendingIntent.FLAG_IMMUTABLE);

En Android 11 (nivel de API 30) y versiones posteriores, debes especificar qué campos deben ser mutables, lo que mitiga las vulnerabilidades accidentales de este tipo.

Recursos


Riesgo: Reproducción de intents pendientes

Se puede volver a reproducir un PendingIntent, a menos que se haya configurado la marca FLAG_ONE_SHOT. Es importante usar FLAG_ONE_SHOT para evitar ataques de reproducción (realizar acciones que no se deben repetir).

Impacto

El impacto de esta vulnerabilidad varía según la implementación del extremo receptor del intent. Una app maliciosa que se aprovecha de un PendingIntent que se creó sin configurar la marca FLAG_ONE_SHOT podría capturar y reutilizar el intent para repetir acciones que solo se deberían realizar una vez.

Mitigaciones

Los intents pendientes no destinados a activarse varias veces deben usar la marca FLAG_ONE_SHOT para evitar ataques de reproducción.

Kotlin

val pendingIntent =
      PendingIntent.getActivity(
          context,
          /* requestCode = */ 0,
          Intent(intentAction),
          PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT)

Java

PendingIntent pendingIntent =
        PendingIntent.getActivity(
            getContext(),
            /* requestCode= */ 0,
            new Intent(intentAction),
            PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);

Recursos


Recursos