Cómo definir un permiso de app personalizado

En este documento, se describe cómo los desarrolladores de apps pueden usar las funciones de seguridad proporcionadas por Android para definir sus propios permisos. Cuando se definen permisos personalizados, una app puede compartir sus recursos y capacidades con otras apps. Para obtener más información sobre los permisos, consulta la Descripción general de los permisos.

Contexto

Android es un sistema operativo separado por privilegios, en el que cada app se ejecuta con una identidad de sistema distinta (ID de grupo e ID de usuario de Linux). Hay partes del sistema que también se separan en identidades distintas. Por lo tanto, Linux aísla las apps entre sí y del sistema.

Las apps pueden exponer su funcionalidad a otras apps. Para hacerlo, se definen los permisos que esas otras apps pueden solicitar. También pueden definir permisos que se ponen automáticamente a disposición de cualquier otra app que esté firmada con el mismo certificado.

Firma de apps

Todos los APK deben estar firmados con un certificado cuya clave privada esté en manos de su desarrollador. Ese certificado identifica al autor de la app. No es necesario que el certificado esté firmado por una autoridad certificada; está permitido, y es común, que las apps para Android utilicen certificados autofirmados. El propósito de los certificados en Android es identificar a los autores de las apps. Esto permite que el sistema otorgue o rechace el acceso a permisos de nivel de firma de las apps y otorgue o rechace la solicitud de una app para tener la misma identidad de Linux que otra.

ID de usuario y acceso a archivos

En el momento de la instalación, Android proporciona a cada paquete un ID de usuario de Linux distinto. La identidad es la misma durante toda la duración del paquete en ese dispositivo. En un dispositivo diferente, el mismo paquete puede tener un UID diferente; lo importante es que cada paquete tenga un UID distinto en un dispositivo determinado.

Debido a que el cumplimiento de la seguridad ocurre en el nivel del proceso, el código de dos paquetes aleatorios normalmente no puede ejecutarse en el mismo proceso, ya que deben ejecutarse como usuarios de Linux diferentes. Puedes usar el atributo sharedUserId en la etiqueta manifest de AndroidManifest.xml de cada paquete para que se les asigne el mismo ID de usuario. De esta manera, por motivos de seguridad, los dos paquetes se consideran la misma app, con el mismo ID de usuario y los mismos permisos de archivo. Ten en cuenta que, para mantener la seguridad, solo dos apps firmadas con la misma firma (y que solicitan el mismo sharedUserId) recibirán el mismo ID de usuario.

Todos los datos almacenados por una app recibirán el ID de usuario de esa app y, en general, no serán accesibles para otros paquetes.

Para obtener más información sobre el modelo de seguridad de Android, consulta la Descripción general de seguridad de Android.

Cómo definir y aplicar permisos

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

Por ejemplo, una app que quisiera controlar quién puede iniciar una de sus actividades podría declarar un permiso para esa operación de la siguiente 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 estén firmados con el mismo certificado. Si un paquete declara un permiso, el sistema no permite al usuario instalar otros paquetes con el mismo nombre de permiso, a menos que estén firmados con el mismo certificado que el primer paquete. Para evitar la repetición de nombres, recomendamos usar nombres de estilo de dominio inverso para los permisos personalizados, por ejemplo, com.example.myapp.ENGAGE_HYPERSPACE.

Se requiere el atributo protectionLevel, que le dice al sistema cómo debe informar al usuario de las apps que requieren el permiso, o quién puede tener ese permiso, como se describe en la documentación vinculada.

El atributo android:permissionGroup es opcional y solo se usa para ayudar al sistema a mostrar permisos al usuario. En la mayoría de los casos, debes establecer esto en un grupo de sistema estándar (que se detalla en android.Manifest.permission_group), aunque puedes definir un grupo por tu cuenta. Es preferible usar un grupo existente, ya que esto simplifica la IU de permiso que se muestra al usuario.

Debes proporcionar una etiqueta y una descripción para el permiso. Estos son recursos de strings que el usuario puede ver cuando consulta una lista de permisos (android:label) o detalles de un solo permiso (android:description). La etiqueta debe ser corta; unas palabras que describan la parte clave de funcionalidad que protege el permiso. La descripción debe incluir un par de oraciones que expliquen lo que el permiso permite que haga un usuario. Nuestra convención es un texto de dos oraciones: en la primera oración, se describe el permiso y, en la segunda, se advierte al usuario del tipo de cosas que pueden fallar si se otorga el permiso a una app.

A continuación, se incluye 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 app to call
    phone numbers without your intervention. Malicious apps may
    cause unexpected calls on your phone bill. Note that this does not
    allow the app to call emergency numbers.</string>

Cómo crear un grupo de permisos

Como se muestra en la sección anterior, puedes usar el atributo android:permissionGroup para ayudar al sistema a describir permisos al usuario. En la mayoría de los casos, te conviene establecer esto en un grupo de sistema estándar (que se detalla en android.Manifest.permission_group), pero también puedes definir tu propio grupo con <permission-group>.

El elemento <permission-group> define una etiqueta para un conjunto de permisos, tanto los declarados en el manifiesto con elementos <permission> como aquellos declarados en otro lugar. Esto solo afecta a la forma en que se agrupan los permisos cuando se presentan al usuario. El elemento <permission-group> no especifica los permisos que pertenecen al grupo, sino que le da un nombre al grupo.

Para colocar un permiso en el grupo, asigna el nombre del grupo al atributo permissionGroup del elemento <permission>.

El elemento <permission-tree> declara un espacio de nombres a un grupo de permisos definidos en el código.

Recomendaciones de permisos personalizados

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

  • Si estás diseñando un conjunto de apps que exponen funcionalidades entre sí, intenta desarrollar las apps para que cada permiso se defina una sola vez. Debes hacerlo si las apps no están todas firmadas con el mismo certificado. Incluso si lo están, la práctica recomendada es definir cada permiso una sola vez.
  • Si la funcionalidad solo está disponible para apps firmadas con la misma firma que la app proveedora, es posible que puedas evitar la definición de permisos personalizados por medio de comprobaciones de firma. Cuando una de tus apps envía una solicitud a otra de tus apps, la segunda puede verificar que ambas estén firmadas con el mismo certificado antes de completar la solicitud.

Continúa leyendo:

<uses-permission>
Contiene referencia de API para la etiqueta del manifiesto que declara los permisos del sistema obligatorios de tu app.

También te puede interesar:

Descripción general de la seguridad de Android
Incluye un análisis detallado del modelo de seguridad de la plataforma de Android.