Cómo determinar el acceso a datos sensibles

El objetivo de un permiso es proteger la privacidad del usuario de Android. Las apps para Android deben solicitar permiso para acceder a datos sensibles del usuario (como contactos y SMS) y algunas funciones del sistema (como la cámara e Internet). Según la función, el sistema podría otorgar automáticamente el permiso o pedirle al usuario que apruebe la solicitud.

Un punto central del diseño de la arquitectura de seguridad de Android consiste en que ninguna app, de manera predeterminada, tiene permiso para realizar operaciones que pudieran tener consecuencias negativas para otras apps, el sistema operativo o el usuario. Esto incluye leer datos privados de los usuarios o escribir en ellos (por ejemplo, los contactos o los mensajes de correo electrónico), leer archivos de otra app o escribir en ellos, acceder a una red, mantener el dispositivo activo, etc.

En esta página, se ofrece una descripción general de cómo funcionan los permisos de Android y se incluye la siguiente información: cómo se presentan los permisos al usuario, la diferencia entre solicitudes de permisos de tiempo de instalación y tiempo de ejecución, cómo se aplican los permisos, y los tipos de permisos y sus grupos. En cambio, si buscas una guía sobre cómo usar los permisos de las apps, consulta Cómo solicitar permisos de la app.

Aprobación de un permiso

Una app debe publicitar los permisos que requiere incluyendo etiquetas <uses-permission> en el manifiesto de la app. Por ejemplo, en el manifiesto de una app que necesite enviar mensajes SMS debería incluirse esta línea:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.example.snazzyapp">

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

        <application ...>
            ...
        </application>
    </manifest>
    

Si en el manifiesto de tu app se incluyen permisos normales (es decir, los que no presentan un gran riesgo para la privacidad del usuario o el funcionamiento del dispositivo), el sistema otorga automáticamente esos permisos.

Si en el manifiesto de tu app se incluyen permisos riesgosos (es decir, los que podrían afectar la privacidad del usuario o el funcionamiento normal del dispositivo), como el permiso de SEND_SMS del ejemplo anterior, el sistema solicita al usuario que otorgue explícitamente esos permisos.

Para obtener más información sobre los permisos normales y riesgosos, consulta Niveles de protección.

Solicitudes para permisos riesgosos

Solo los permisos riesgosos requieren la aprobación del usuario. El modo en que Android le pide al usuario que otorgue permisos riesgosos depende de la versión del sistema que se ejecuta en el dispositivo del usuario y de la versión del sistema a la que se orienta tu app.

Solicitudes de tiempo de ejecución (Android 6.0 y posteriores)

Si el dispositivo tiene instalado Android 6.0 (API nivel 23) o versiones posteriores, y si el atributo targetSdkVersion de la app es de nivel 23 o superior, el usuario no recibe notificaciones de permisos de ninguna app durante la instalación. Tu app debe pedirle al usuario que otorgue permisos riesgosos durante el tiempo de ejecución. Cuando la app solicita un permiso, el usuario ve un diálogo del sistema (como el que se muestra en la figura 1, a la izquierda) que le indica a qué grupo de permisos está intentando acceder la app. El diálogo incluye los botones Rechazar y Permitir.

Si el usuario rechaza la solicitud de permiso, la próxima vez que la app solicite el permiso, el diálogo incluirá una casilla de verificación que, si se marca, indicará que el usuario no desea que se le vuelva a pedir el permiso (consulta la figure 1, a la derecha).

Figura 1: Diálogo de permiso inicial (izquierda) y solicitud de permiso secundaria con opción de desactivar las solicitudes posteriores (derecha)

Si el usuario marca la casilla No volver a preguntar y presiona Rechazar, el sistema ya no le hará pedidos al usuario si vuelves a intentar solicitar el mismo permiso.

Incluso si el usuario le otorga a la app el permiso que solicitó, esto no te garantizará que siempre lo tendrás. Además, los usuarios tienen la opción de habilitar o inhabilitar permisos uno por uno en la configuración del sistema. Siempre deberías verificar y solicitar permisos durante el tiempo de ejecución, a fin de evitar errores durante de tiempo de ejecución (SecurityException).

Para obtener detalles sobre cómo manejar las solicitudes de permiso de tiempo de ejecución, consulta Cómo solicitar permisos de la app.

Solicitudes en el momento de la instalación (Android 5.1.1 y anteriores)

Si el dispositivo tiene instalado Android 5.1.1 (API nivel 22) o versiones anteriores, o si el atributo targetSdkVersion es 22 o inferior y se ejecuta en cualquier versión de Android, el sistema pide automáticamente al usuario que otorgue todos los permisos riesgosos para tu app en el momento de la instalación (consulta la figura 2).

Figura 2: Diálogo de permiso en el momento de la instalación

Si el usuario hace clic en Aceptar, se otorgan todos los permisos solicitados por la app. Si el usuario rechaza la solicitud de permisos, el sistema cancela la instalación de la app.

Si para instalar una actualización de la app se requieren permisos adicionales, se le pide al usuario que acepte los nuevos permisos antes de actualizar la app.

Para obtener una descripción general de los patrones recomendados para la experiencia del usuario a fin de solicitar permisos, consulta Prácticas recomendadas de permisos de la app.

Para obtener información sobre cómo verificar y solicitar permisos del usuario, consulta Cómo solicitar permisos de la app.

Solicitudes para acceder a información sensible del usuario

Algunas apps dependen del acceso a información sensible del usuario, relacionada con registros de llamadas y mensajes SMS. Si quieres solicitar los permisos específicos para registros de llamadas y mensajes SMS y publicar tu app en Play Store, debes solicitar al usuario que configure tu app como controlador predeterminado para una función de sistema principal antes de solicitar estos permisos de tiempo de ejecución.

Para obtener más información acerca de los controladores predeterminados, incluida la orientación acerca de cómo mostrar una solicitud de controlador predeterminado a los usuarios, consulta la guía sobre permisos que se usan solo en controladores predeterminados.

Permisos para funciones de hardware opcionales

Para acceder a algunas funciones de hardware (como Bluetooth o r la cámara), se necesita un permiso de la app. Sin embargo, no todos los dispositivos Android cuentan con estas funciones de hardware. De modo que, si tu app solicita el permiso de CAMERA, es importante que también incluyas la etiqueta <uses-feature> en tu manifiesto a fin de declarar si se requiere o no esta función. Por ejemplo:

<uses-feature android:name="android.hardware.camera" android:required="false" />
    

Si declaras android:required="false" para la función, Google Play permitirá que tu app se instale en dispositivos que no cuentan con esa función. Luego, para verificar si el dispositivo actual tiene la función durante el tiempo de ejecución, llama a PackageManager.hasSystemFeature() e inhabilita esa función de manera fluida, si no está disponible.

Si no proporcionas la etiqueta <uses-feature>, cuando Google Play detecte que tu app solicita el permiso correspondiente, asumirá que requiere esta función. De este modo, filtra tu app desde dispositivos que no cuentan con la función, como si declararas android:required="true" en la etiqueta <uses-feature>.

Para obtener más información, consulta Google Play y filtrado por funciones

Aplicación de permisos

Los permisos no solo se utilizan para solicitar funcionalidades del sistema. Los servicios proporcionados por las apps pueden aplicar permisos personalizados para limitar su uso a determinados usuarios. Para obtener más información sobre cómo declarar permisos personalizados, consulta Cómo definir un permiso personalizado de una app.

Aplicación de permisos de actividad

Los permisos aplicados con el atributo android:permission en la etiqueta <activity> en el manifiesto fijan restricciones respecto a los usuarios que pueden iniciar esa Activity. El permiso se verifica durante Context.startActivity() y Activity.startActivityForResult(). Si el emisor no tiene el permiso necesario, la llamada arroja una SecurityException.

Aplicación de permiso de servicio

Los permisos aplicados con el atributo android:permission en la etiqueta <service> en el manifiesto fijan restricciones respecto a los usuarios que pueden iniciarlo o vincularlo con el Service asociado. El permiso se verifica durante Context.startService(), Context.stopService() y Context.bindService(). Si el emisor no tiene el permiso necesario, la llamada arroja una SecurityException.

Aplicación de permiso de emisión

Los permisos aplicados con el atributo android:permission en la etiqueta <receiver> fijan restricciones respecto de la autorización para enviar transmisiones al receptor asociado. BroadcastReceiver. El permiso se controla después de que se muestra Context.sendBroadcast(), mientras el sistema intenta proporcionar la transmisión enviada al receptor en cuestión. En consecuencia, un error de permisos no generará una excepción para el emisor; no proporcionará la Intent.

De la misma manera, se puede suministrar un permiso a Context.registerReceiver() para tener control sobre quiénes pueden realizar transmisiones a un receptor registrado programáticamente. Por otro lado, se puede suministrar un permiso cuando se llama a Context.sendBroadcast()a fin de restringir los objetos receptores de emisión que tienen autorización para recibir la transmisión.

Ten en cuenta que tanto un receptor como un transmisor pueden requerir un permiso. Cuando esto sucede, ambos controles de permisos deben aprobarse para que la intent se proporcione al objetivo asociado. Para obtener más información, consulta Cómo usar permisos para restringir emisiones.

Aplicación de permiso de proveedor de contenido

Los permisos aplicados con el atributo android:permission en la etiqueta <provider> fijan restricciones respecto a quiénes pueden acceder a los datos en un ContentProvider. (Los proveedores de contenido disponen de un recurso adicional importante que se denomina permisos del URI y se describe a continuación). A diferencia de los otros componentes, puedes establecer dos atributos de permisos separados: android:readPermission restringe quién puede leer del proveedor y android:writePermission restringe quién puede escribir en él. Ten en cuenta que si un proveedor está protegido con un permiso de escritura y un permiso de lectura, tener el permiso de escritura no implica que puedas realizar operaciones de lectura en un proveedor.

Los permisos se controlan cuando obtienes un proveedor por primera vez (si no tienes ninguno de los permisos, se generará una SecurityException) y cuando realizas operaciones en el proveedor. Para usar ContentResolver.query(), se debe tener el permiso de lectura; para usar ContentResolver.insert(), ContentResolver.update() y ContentResolver.delete(), se debe tener el permiso de escritura. En todos estos casos, si no tienes el permiso obligatorio, la llamada genera SecurityException.

Permisos de URI

El sistema de permisos estándar descrito hasta ahora suele no ser suficiente cuando se usa con proveedores de contenido. Un proveedor de contenido puede desear protegerse con permisos de lectura y escritura, mientras que sus clientes directos también deben proporcionar URI específicos a otras apps para que puedan operar en ellas.

Un ejemplo típico es el de los archivos adjuntos en la app de correo electrónico. El acceso al correo debe estar protegido por permisos, ya que son datos confidenciales del usuario. Sin embargo, si un URI de una imagen adjunta se proporciona a un visor de imágenes, este no tendrá permiso para abrir el archivo adjunto, debido a que no existirá un motivo para que tenga un permiso que le permita acceder a todo el correo electrónico.

La solución para este problema son los permisos por URI: cuando inicia una actividad o muestra un resultado en una actividad, el emisor puede establecer Intent.FLAG_GRANT_READ_URI_PERMISSION o Intent.FLAG_GRANT_WRITE_URI_PERMISSION. Esto otorga a la actividad receptora permisos de acceso al URI de datos específico en la intent, independientemente de que tenga permiso para acceder a los datos en el proveedor de contenido correspondiente a la intent.

Este mecanismo permite emplear un modelo de estilo de capacidad común en el cual la interacción del usuario (abrir un archivo adjunto, seleccionar un contacto de una lista, etc.) impulsa el otorgamiento de permisos específicos. Este puede ser un recurso clave para reducir los permisos que necesitan las apps únicamente a aquellos relacionados de manera directa con su comportamiento.

Para crear la implementación más segura que permita a otras apps tomar la responsabilidad de sus acciones dentro de tu app, debes usar permisos específicos de esta manera y declarar la compatibilidad de la app con el atributo android:grantUriPermissions o la etiqueta <grant-uri-permissions>.

Se ofrece más información en los métodos Context.grantUriPermission(), Context.revokeUriPermission() y Context.checkUriPermission().

Aplicación de otros permisos

Los permisos específicos arbitrarios se pueden aplicar en cualquier llamada a un servicio. Esto se logra con el método Context.checkCallingPermission(). Realiza una llamada con la string de permiso, que mostrará un número entero que indicará si se otorgó ese permiso al proceso de llamada actual. Ten en cuenta que esto solo se puede usar cuando ejecutas una llamada que ingresa de otro proceso; por lo general, mediante una interfaz IDL publicada por un servicio o proporcionada de alguna manera diferente a otro proceso.

Existen varias otras formas útiles de controlar los permisos. Si tienes el PID de otro proceso, puedes usar el método contextual Context.checkPermission() para verificar un permiso según ese PID. Si tienes el nombre del paquete de otra app, puedes usar el método PackageManager.checkPermission() para averiguar si se le otorgó un permiso específico a ese paquete en particular.

Ajustes automáticos de permisos

Con el tiempo, es posible que se agreguen restricciones nuevas a la plataforma a fin de que, para usar determinadas API, tu app deba solicitar un permiso que antes no necesitaba. Debido a que las apps existentes suponen que el acceso a esas API es libre, Android puede implementar la solicitud del permiso nuevo en el manifiesto de la app para evitar dañarla en la versión nueva de la plataforma. Android toma las decisiones relacionadas con el hecho de que una app pueda necesitar el permiso según el valor indicado para el atributo targetSdkVersion. Si el valor es inferior al de la versión en la cual el permiso se agregó, Android agrega el permiso.

Por ejemplo, el permiso READ_EXTERNAL_STORAGE se aplica a partir de la API nivel 19 para restringir el acceso a los espacios de almacenamiento compartido. Si tu atributo targetSdkVersion es 18 o inferior, este permiso se agrega a la app en versiones nuevas de Android.

Precaución: Si un permiso se agrega automáticamente a tu app, en Google Play, la app indicará que necesita estos permisos adicionales aunque podría no necesitarlos realmente. Para evitar esto y quitar los permisos predeterminados que no necesitas, siempre actualiza el atributo targetSdkVersion para que tenga el valor más alto posible. Para ver los permisos agregados en cada versión, consulta la documentación de Build.VERSION_CODES.

Niveles de protección

Los permisos se dividen en varios niveles de protección. El nivel de protección determina si se necesitan solicitudes de permiso de tiempo de ejecución.

Hay tres niveles de protección que afectan a apps de terceros: permisos normales, de firma y riesgosos. Para ver el nivel de protección de un permiso en particular, visita la página de referencia de la API de permisos.

Permisos normales

Los permisos normales abarcan áreas en las cuales tu app tiene que acceder a datos o recursos fuera de su zona de pruebas, pero donde existe un riesgo mínimo para la privacidad del usuario o el funcionamiento de otras apps. Por ejemplo, el permiso para establecer el huso horario es un permiso normal.

Si una app declara que necesita un permiso normal, el sistema le otorga automáticamente el permiso. El sistema no le solicita al usuario que otorgue permisos normales y los usuarios no pueden revocar estos permisos.

Permisos de firma

El sistema otorga estos permisos en el momento de la instalación, pero solo cuando la app que intenta usar un permiso tiene la firma del mismo certificado que la app que define el permiso.

Permisos riesgosos

Los permisos riesgosos abarcan áreas en las cuales la app requiere datos o recursos que incluyen información privada del usuario, o bien que podrían afectar los datos almacenados del usuario o el funcionamiento de otras apps. Por ejemplo, la capacidad de leer los contactos del usuario es un permiso riesgoso. Si una app declara que necesita un permiso riesgoso, el usuario tiene que otorgarle explícitamente el permiso. Hasta que el usuario aprueba el permiso, la app no puede ofrecer funcionalidades que dependan de ese permiso.

Para usar un permiso riesgoso, tu app debe solicitar al usuario que otorgue el permiso durante el tiempo de ejecución. Para obtener más detalles sobre cómo se le solicitan permisos al usuario, consulta Solicitud de permiso riesgoso.

Permisos especiales

Un par de permisos no se comportan como normales ni riesgosos. SYSTEM_ALERT_WINDOW y WRITE_SETTINGS son particularmente confidenciales; por ello, la mayoría de las apps no deben usarlos. Si una app necesita uno de estos permisos, debe declararlo en el manifiesto y enviar una intent en la que solicite la autorización del usuario. El sistema responde a la intent mostrando una pantalla de administración detallada al usuario.

Para obtener información sobre cómo solicitar estos permisos, consulta las entradas de referencia SYSTEM_ALERT_WINDOW y WRITE_SETTINGS.

Los permisos que proporciona el sistema Android se pueden encontrar en Manifest.permission.

Grupos de permisos

Los permisos se organizan en grupos relacionados con las capacidades o funciones de un dispositivo. En este sistema, las solicitudes de permisos se controlan a nivel grupal y un grupo de permisos individual corresponde a varias declaraciones de permisos en el manifiesto de la app; por ejemplo, el grupo SMS incluye las declaraciones READ_SMS y RECEIVE_SMS. Agrupar permisos de esta manera permite al usuario tomar decisiones más significativas y fundamentadas sin verse abrumado por solicitudes de permisos complejas y técnicas.

Todos los permisos riesgosos de Android pertenecen a grupos de permisos. Cualquier permiso puede pertenecer a un grupo de permisos, independientemente del nivel de protección. Sin embargo, el grupo de un permiso solo afecta la experiencia del usuario si es riesgoso.

Si el dispositivo tiene Android 6.0 (API nivel 23) instalado y el atributo targetSdkVersion de la app es 23 o un valor superior, el siguiente comportamiento del sistema tiene lugar cuando tu app solicita un permiso riesgoso:

  • Si la app no tiene permisos actualmente en el grupo de permisos, el sistema muestra al usuario el diálogo de solicitud de permiso en el que se describe el grupo de permisos al cual la app desea acceder. En diálogo, no se describe el permiso específico dentro de ese grupo. Por ejemplo, si una app solicita el permiso READ_CONTACTS, el diálogo del sistema solo indica que la app necesita acceder a los contactos del dispositivo. Si el usuario brinda la aprobación, el sistema otorga a la app solamente el permiso que solicitó.
  • Si la app ya tiene otro permiso riesgoso en el mismo grupo de permisos, el sistema otorga de inmediato el permiso, sin interactuar con el usuario. Por ejemplo, si a una app ya se le otorgó el permiso READ_CONTACTS y luego esta solicita el permiso WRITE_CONTACTS, el sistema lo otorga de inmediato.

Precaución: Es posible que las versiones futuras del SDK de Android trasladen un permiso en particular de un grupo a otro. Por lo tanto, no debes basar la lógica de tu app en la estructura de estos grupos de permisos.

Por ejemplo, READ_CONTACTS está en el mismo grupo de permisos que WRITE_CONTACTS desde Android 8.1 (API nivel 27). Si tu app solicita el permiso READ_CONTACTS y, luego, solicita el permiso WRITE_CONTACTS, no debes asumir que el sistema puede otorgar automáticamente el permiso WRITE_CONTACTS.

Si el dispositivo tiene instalado Android 5.1 (API nivel 22) o versiones anteriores, o si el atributo targetSdkVersion de la app es 22 o inferior, el sistema solicita al usuario que otorgue el permiso en el momento de la instalación. Nuevamente, el sistema solo dice al usuario qué grupos de permisos necesita la app y no los permisos individuales. Por ejemplo, cuando una app solicita READ_CONTACTS, el diálogo de instalación enumera el grupo Contactos. Cuando el usuario acepta, solo se otorga el permiso READ_CONTACTS a la app.

Nota: De todos modos, tu app debe solicitar explícitamente cada uno de los permisos que necesita aunque el usuario haya otorgado otro del mismo grupo. Además, la agrupación de permisos puede modificarse en futuras versiones de Android. Tu código no debería tener una lógica que dependa de un conjunto de permisos en particular que estén dentro de un mismo grupo.

Cómo ver los permisos de una app

Puedes ver todos los permisos definidos actualmente en el sistema usando la app Settings y el comando shell adb shell pm list permissions. Para usar la app Settings, ve a Settings > Apps. Elige una app y desplázate hacia abajo para ver los permisos que usa. Para los desarrolladores, la opción "-s" de la herramienta adb muestra los permisos con un aspecto similar al que observarán los usuarios:

    $ adb shell pm list permissions -s
    All Permissions:

    Network communication: view Wi-Fi state, create Bluetooth connections, full
    internet access, view network state

    Your location: access extra location provider commands, fine (GPS) location,
    mock location sources for testing, coarse (network-based) location

    Services that cost you money: send SMS messages, directly call phone numbers

    ...
    

Además, puedes usar la opción -g de adb para otorgar automáticamente todos los permisos cuando instales una app en un emulador o un dispositivo de prueba:

    $ adb shell install -g MyApp.apk
    

Recursos adicionales