Skip to content

Most visited

Recently visited

navigation

Permisos del sistema

Patrones de diseño

Permisos

Video

Google I/O 2015; Permisos de Android M: Prácticas recomendadas para desarrolladores

Android es un sistema operativo con privilegios independientes, en el que cada aplicación se ejecuta con una identidad de sistema distinta (ID de usuario de Linux y ID de grupo). También se separan partes del sistema en identidades distintas. Así, Linux aísla las aplicaciones entre sí y del sistema operativo.

Se ofrecen funciones de seguridad adicionales más precisas mediante un mecanismo de “permisos” que aplica restricciones en las operaciones específicas para que un proceso en particular puede realizar y permisos por URI para la dar acceso ad-hoc a elementos específicos de datos.

En este documento, se describe la manera en que los desarrolladores de aplicaciones pueden usar las funciones de seguridad provistas por Android. Se brinda información más general sobre seguridad de Android en el Proyecto de Código Abierto de Android.

Arquitectura de seguridad

Un punto central del diseño de la arquitectura de seguridad de Android consiste en que ninguna aplicación, de manera predeterminada, tiene permiso para realizar operaciones que pudieran tener consecuencias negativas para otras aplicaciones, 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 aplicación o escribir en ellos, acceder a una red, mantener el dispositivo activo, etc.

Debido a que cada aplicación de Android funciona en una zona de pruebas de proceso, las aplicaciones deben compartir recursos y datos de manera explícita. Hacen esto declarando los permisos que necesitan para capacidades adicionales no previstas por la zona de pruebas básica. Las aplicaciones declaran estáticamente los permisos que necesitan y el sistema Android solicita al usuario su consentimiento.

La zona de pruebas de aplicaciones no depende de la tecnología empleada para crear una aplicación. En especial, la VM Dalvik no supone un límite de seguridad y cualquier app puede ejecutar código nativo (consulta el NDK de Android). Todos los tipos de aplicaciones (Java, nativas e híbridas) se colocan en zonas de pruebas de la misma manera y tienen el mismo grado de seguridad.

Firma de aplicaciones

Todos los APK (archivos .apk) deben estar firmados con un certificado cuya clave privada esté en manos del desarrollador. Este certificado identifica al autor de la aplicación. No es necesario que el certificado lleve la firma de una autoridad de certificación; es perfectamente admisible, y común, que las aplicaciones de Android usen certificados autofirmados. El objetivo de los certificados de Android es distinguir a los autores de las aplicaciones. Esto permite al sistema otorgar o denegar a las aplicaciones el acceso a permisos de nivel de firma y otorgar o denegar a una aplicación una solicitud para usar la misma la identidad de Linux que otra aplicación.

ID de usuario y acceso a archivos

En el momento de la instalación, Android asigna a cada paquete un ID de usuario de Linux distinto. La identidad se mantiene constante durante la vida útil del paquete en ese dispositivo. En un dispositivo diferente, el mismo paquete puede tener otro ID de usuario; lo que importa es que cada paquete tenga un ID de usuario distinto en un dispositivo determinado.

Debido a que la aplicación de la seguridad tiene lugar en el nivel del proceso, el código de dos paquetes cualesquiera normalmente no puede ejecutarse en el mismo proceso, ya que deben funcionar como diferentes usuarios de Linux. Puedes usar el atributo sharedUserId en la etiqueta manifest de AndroidManifest.xml de cada uno de los paquetes para que se les asigne el mismo ID de usuario. Al hacer esto, por motivos de seguridad, los dos paquetes se tratan como si fueran una misma aplicación, con el mismo ID de usuario y permisos de archivo. Ten en cuenta que, a fin de mantener la seguridad, solo se asignará el mismo ID de usuario a dos aplicaciones que tengan la misma firma (y soliciten el mismo sharedUserId).

A los datos almacenados por una aplicación se les asignará el ID de usuario de esta; además, normalmente otros paquetes no podrán acceder a ellos. Al crear un archivo nuevo con getSharedPreferences(String, int), openFileOutput(String, int) o openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), puedes usar los indicadores MODE_WORLD_READABLE o MODE_WORLD_WRITEABLE para permitir que cualquier otro paquete realice operaciones de lectura y escriba en él. Al establecer estos indicadores, el archivo sigue siendo propiedad de tu aplicación, pero sus permisos de lectura y escritura generales se han configurado adecuadamente para que cualquier otra aplicación pueda verlo.

Uso de permisos

Una aplicación básica de Android no tiene permisos asociados de manera predeterminada. Esto significa que no puede hacer nada que afecte negativamente la experiencia del usuario o los datos en el dispositivo. Para usar funciones protegidas del dispositivo, debes incluir una o más etiquetas <uses-permission> en el manifiesto de tu app.

Por ejemplo, una aplicación que tiene que controlar los mensajes SMS entrantes especificaría lo siguiente:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    ...
</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), el sistema solicita al usuario que otorgue explícitamente esos permisos. La manera en que Android realiza la solicitud depende de la versión del sistema y la versión del sistema objetivo de tu app:

Muchas veces, un error en los permisos hará que se envíe SecurityException a la aplicación. Sin embargo, no es seguro que esto ocurra en todos lados. Por ejemplo, el método sendBroadcast(Intent) controla los permisos a medida que los datos se proporcionan a cada receptor, una vez que se devuelve la llamada del método, para que no recibas una excepción si hay errores en los permisos. En la mayoría de los casos, no obstante, se asentará un error de permisos en el registro del sistema.

Los permisos que proporciona el sistema Android se pueden encontrar en Manifest.permission. Cualquier aplicación también puede definir y aplicar sus propios permisos, por lo cual esta no es una lista completa de todos los permisos posibles.

Un permiso en particular se puede aplicar en varios puntos durante el funcionamiento de tu programa:

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 WRITE_EXTERNAL_STORAGE se agregó en el nivel de API 4 para restringir el acceso a los espacios de almacenamiento compartido. Si tu atributo targetSdkVersion es 3 o inferior, este permiso se agrega a la app en versiones nuevas de Android.

Advertencia: Si un permiso se agrega automáticamente a tu app, en Google Play, tu 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. En la documentación de Build.VERSION_CODES, puedes ver los permisos agregados en cada versión.

Permisos normales y riesgosos

Los permisos del sistema se dividen en varios niveles de protección. Los dos niveles más importantes que debes conocer son el normal y el riesgoso.

Grupos de permisos

Todos los permisos riesgosos del sistema Android pertenecen a grupos de permisos. Si el dispositivo tiene Android 6.0 (nivel de API 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:

Cualquier permiso puede pertenecer a un grupo de permisos; entre ellos, los normales y los que define tu app. Sin embargo, el grupo de un permiso solo afecta la experiencia del usuario si es riesgoso. Puedes ignorar el grupo de permisos para los permisos normales.

Si el dispositivo tiene instalado Android 5.1 (nivel de API 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.

Tabla 1. Permisos riesgosos y grupos de permisos.

Grupo de permisos Permisos
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

Definición y aplicación de permisos

Para aplicar tus propios permisos, primero debes declararlos en AndroidManifest.xml con uno o más elementos <permission>.

Por ejemplo, una aplicación en la que se busca tener control sobre quiénes pueden iniciar una de las actividades de esta podría declarar un permiso para esta operación de esta manera:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp" >
    <permission android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
        android:label="@string/permlab_deadlyActivity"
        android:description="@string/permdesc_deadlyActivity"
        android:permissionGroup="android.permission-group.COST_MONEY"
        android:protectionLevel="dangerous" />
    ...
</manifest>

Nota: El sistema no permite que varios paquetes declaren un permiso con el mismo nombre, a menos que todos los paquetes estén firmados con el mismo certificado. Si un paquete declara un permiso, el sistema no permite que el usuario instale otros paquetes con el mismo nombre de permiso, a menos que esos paquetes estén firmados con el mismo certificado que el primero. Para evitar conflictos de nombres, recomendamos usar la notación de nombre de dominio inverso para los permisos personalizados; por ejemplo, com.example.myapp.ENGAGE_HYPERSPACE.

El atributo protectionLevel es obligatorio e indica al sistema la manera en que se debe informar al usuario cuando las aplicaciones requieren el permiso o quién está autorizado a tener ese permiso, como se describe en la documentación del vínculo.

El atributo android:permissionGroup es opcional y solo se usa para ayudar al sistema a mostrar los permisos al usuario. En la mayoría de los casos, puedes establecer este atributo en un grupo estándar del sistema (mencionado en android.Manifest.permission_group), aunque puedes definir un grupo tú mismo. Se recomienda usar un grupo existente, ya que esto simplifica la IU de permisos que se muestra al usuario.

Debes incluir un nombre y una descripción para el permiso. Estos son recursos de strings que el usuario puede ver cuando mira una lista de permisos (android:label) o información detallada de un único permiso (android:description). El nombre debe ser corto; solo unas pocas palabras que describan la funcionalidad clave que el permiso protege. La descripción debe constar de un par de oraciones que describan lo que el permiso autoriza al portador. Por convención, usamos una descripción de dos oraciones: en la primera se describe el permiso y en la segunda se advierte al usuario sobre lo que puede salir mal si se otorga el permiso a una aplicación.

A continuación se ofrece un ejemplo de una etiqueta y una descripción para el permiso CALL_PHONE:

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the application to call
    phone numbers without your intervention. Malicious applications may
    cause unexpected calls on your phone bill. Note that this does not
    allow the application to call emergency numbers.</string>

Puedes ver 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, dirígete a Settings > Applications. 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

...

Recomendaciones de permisos personalizados

Las apps pueden definir permisos personalizados propios y solicitar permisos personalizados de otras apps definiendo los elementos <uses-permission>. Sin embargo, debes analizar cuidadosamente si es necesario que tu app lo haga.

Aplicación de permisos en AndroidManifest.xml

Puedes implementar permisos de alto nivel que restringen el acceso a todos los componentes del sistema o la aplicación a través de tu AndroidManifest.xml. Para hacer esto, incluye un atributo android:permission en el componente deseado e indica el permiso que controla el acceso al componente.

Los permisos Activity (aplicados a la etiqueta <activity>) fijan restricciones respecto de la autorización para iniciar la actividad asociada. El permiso se controla durante Context.startActivity() y Activity.startActivityForResult(); si el emisor no tiene el permiso obligatorio, la llamada genera SecurityException.

Los permisos Service (aplicados a la etiqueta <service>) fijan restricciones respecto de la autorización para iniciar o vincular el servicio asociado. El permiso se controla durante Context.startService(), Context.stopService() y Context.bindService(); si el emisor no tiene el permiso obligatorio, la llamada genera SecurityException.

Los permisos BroadcastReceiver (aplicados a la etiqueta <receiver>) fijan restricciones respecto de la autorización para enviar transmisiones al receptor asociado. 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. Como 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 BroadcastReceiver que tienen autorización para recibir la transmisión (consulta más adelante).

Los permisos ContentProvider (aplicados a la etiqueta <provider>) fijan restricciones respecto de la autorización para acceder a datos en ContentProvider. (Los proveedores de contenido disponen de un recurso adicional importante que se denomina permisos del URI, que se describe más adelante). 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á 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.

Aplicación de permisos cuando se envían transmisiones

Además del permiso que determina quién puede enviar intents a un BroadcastReceiver registrado (como se describió antes), también puedes especificar un permiso obligatorio cuando se envía una transmisión. Llamando a Context.sendBroadcast() con una string de permiso, se exige que la aplicación de un receptor tenga ese permiso a fin de 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.

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. Esta 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(String, int, int) para verificar un permiso según ese PID. Si tienes el nombre de paquete de otra aplicación, puedes usar el método PackageManager directo PackageManager.checkPermission(String, String) para averiguar si se le otorgó un permiso específico a ese paquete en particular.

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 aplicaciones para que puedan operar en ellas. Un ejemplo típico es el de los archivos adjuntos de una aplicación de correo. 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 aplicaciones únicamente a aquellos relacionados de manera directa con su comportamiento.

El otorgamiento de permisos de URI específicos requiere, sin embargo, cierta cooperación por parte del proveedor de contenido que tiene esos URI. Se recomienda que los proveedores de contenido implementen este recurso y declaren que lo admiten mediante 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().

Continúa leyendo:

Permisos que implican requisitos de funciones
Información sobre cómo la solicitud de algunos permisos restringirá implícitamente tu app a dispositivos que incluyan la característica de hardware o software correspondiente.
<uses-permission>
Referencia de API para la etiqueta del manifiesto que declara los permisos del sistema obligatorios de tu app.
Manifest.permission
Referencia de API para todos los permisos del sistema.

También te puede interesar:

Compatibilidad con dispositivos
Información acerca de cómo funciona Android en diferentes tipos de dispositivos e introducción a la manera en que puedes optimizar tu app para cada dispositivo o restringir la disponibilidad de esta para diferentes dispositivos.
Información general de seguridad de Android
Análisis detallado del modelo de seguridad de la plataforma Android.
This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.