Control de acceso basado en permisos a componentes exportados

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

Descripción general

Un permiso de Android es un identificador de cadena declarado en el manifiesto de la app para solicitar acceso a datos o acciones restringidos, que el framework de Android aplica en el tiempo de ejecución.

Los niveles de permisos de Android indican el riesgo potencial asociado con el permiso:

  • Normal: Permisos de bajo riesgo que se otorgan automáticamente en el momento de la instalación
  • Riesgosos: Permisos de alto riesgo que podrían permitir el acceso a datos sensibles del usuario y que requieren la aprobación explícita del usuario durante el tiempo de ejecución
  • Firma: Se otorga solo a las apps firmadas con el mismo certificado que la app que declara el permiso. Por lo general, se usa para las apps del sistema o las interacciones entre apps del mismo desarrollador.

Las vulnerabilidades relacionadas con los controles de acceso basados en permisos se producen cuando un componente de la app (como una actividad, un receptor, un proveedor de contenido o un servicio) cumple con todos los siguientes criterios:

  • El componente no está asociado a ningún android:permission en el Manifest.
  • El componente realiza una tarea sensible para la que existe un permiso que el usuario ya aprobó.
  • El componente se exporta.
  • El componente no realiza ninguna verificación manual de permisos (a nivel del manifiesto o del código).

Cuando esto sucede, una app maliciosa puede realizar acciones sensibles abusando de los privilegios del componente vulnerable y transfiriendo los privilegios de la app vulnerable a la app maliciosa.

Impacto

La exportación de componentes vulnerables se puede usar para obtener acceso a recursos sensibles o realizar acciones sensibles. El impacto de este comportamiento no deseado depende del contexto del componente vulnerable y sus privilegios.

Mitigaciones

Cómo solicitar permisos para tareas sensibles

Cuando exportes un componente con permisos sensibles, exige esos mismos permisos para cualquier solicitud entrante. El IDE de Android Studio tiene verificaciones de lint para receptores y servicios para detectar esta vulnerabilidad y recomendar que se soliciten los permisos adecuados.

Los desarrolladores pueden exigir permisos para las solicitudes entrantes declarándolos en el archivo Manifest o a nivel del código cuando implementan el servicio, como en los siguientes ejemplos.

XML

<manifest ...>
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application ...>
        <service android:name=".MyExportService"
                 android:exported="true"
                 android:permission="android.permission.READ_CONTACTS" />

        </application>
</manifest>

Kotlin

class MyExportService : Service() {

    private val binder = MyExportBinder()

    override fun onBind(intent: Intent): IBinder? {
        // Enforce calling app has the required permission
        enforceCallingPermission(Manifest.permission.READ_CONTACTS, "Calling app doesn't have READ_CONTACTS permission.")
        // Permission is enforced, proceed with export logic
        return binder
    }

    // Inner class for your Binder implementation
    private inner class MyExportBinder : Binder() {
        // Permission is enforced, proceed with export logic
    }
}

Java

public class MyExportService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // Enforce calling app has the required permission
        enforceCallingPermission(Manifest.permission.READ_CONTACTS, "Calling app doesn't have READ_CONTACTS permission.");

        return binder;

    }

    // Inner class for your Binder implementation
    private class MyExportBinder extends Binder {
        // Permission is enforced, proceed with export logic

    }
}

No exportar el componente

Evita exportar componentes con acceso a recursos sensibles, a menos que sea absolutamente necesario. Para lograr esto, configura android:exported en el archivo Manifest como false para tu componente. A partir del nivel de API 31, este atributo se establece en falsede forma predeterminada.

XML

<activity
    android:name=".MyActivity"
    android:exported="false"/>

Aplica permisos basados en firmas

Cuando compartes datos entre dos apps que controlas o posees, usa permisos basados en firmas. Estos permisos no requieren la confirmación del usuario y, en cambio, comprueban que la app que accede a los datos esté firmada con la misma clave. Esta configuración ofrece una experiencia del usuario más segura y simplificada. Si declaras permisos personalizados, ten en cuenta los lineamientos de seguridad correspondientes.

XML

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

Extremos de tareas únicas

Implementa tu app siguiendo el principio de diseño de Separación de responsabilidades. Cada extremo solo debe realizar un pequeño conjunto de tareas específicas con privilegios específicos. Esta práctica de buen diseño también permite que el desarrollador aplique permisos detallados para cada extremo. Por ejemplo, evita crear un solo extremo que proporcione tanto el calendario como los contactos.

Recursos