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.

Información general

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 APKs deben estar firmados con un certificado cuya clave privada esté en manos de su desarrollador. No es necesario que el certificado lleve la firma de una autoridad certificadora. Es admisible, y común, que las apps para Android usen 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 niegue a las apps el acceso a permisos de nivel de firma y otorgue o niegue la solicitud de una app para tener la misma identidad de Linux que otra app.

Otorga permisos de firma después del momento de fabricación del dispositivo

A partir de Android 12 (nivel de API 31), el atributo knownCerts para permisos de nivel de firma te permite hacer referencia a los resúmenes de los certificados de firma conocidos en el momento de la declaración.

Puedes declarar el atributo knownCerts y usar la marca knownSigner en el atributo protectionLevel de tu app para un permiso determinado de nivel de firma. Posteriormente, el sistema otorga ese permiso a la app solicitante si algún firmante en el linaje de firmas de esa app, incluido el firmante actual, coincide con uno de los resúmenes que se declaró con el permiso en el atributo knownCerts.

La marca knownSigner permite que los dispositivos y las apps otorguen permisos de firma a otras apps sin tener que firmar las apps en el momento de la fabricación y el envío del dispositivo.

IDs 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 podría tener un UID diferente; lo que importa 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.

Todos los datos almacenados por una app reciben el ID de usuario de esa app y, en general, otros paquetes no pueden acceder a ellos.

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 usando uno o más elementos <permission>.

Convención de nombres

El sistema no permite que varios paquetes declaren un permiso con el mismo nombre, a menos que todos se hayan firmado con el mismo certificado. Si un paquete declara un permiso, el sistema tampoco 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.

Te recomendamos que uses prefijos para los permisos con el nombre del paquete de la app usando la denominación de estilo de dominio inverso, seguido por .permission. y, luego, una descripción de la capacidad que el permiso representa, en mayúsculas con guiones bajos. Por ejemplo, com.example.myapp.permission.ENGAGE_HYPERSPACE.

Si sigues esta recomendación, se evitan los conflictos de nombres y se ayuda a identificar claramente el propietario y la intención de un permiso personalizado.

Ejemplo

Por ejemplo, una app que necesita controlar qué otras apps pueden iniciar una de sus actividades puede declarar un permiso para esta operación de la siguiente forma:

<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>

Se requiere el atributo protectionLevel, que le indica al sistema cómo debe informar a los usuarios de las apps que requieren el permiso, o qué apps pueden tener el 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, 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 como se describe en la siguiente sección. Recomendamos usar un grupo existente porque, de esa manera, se simplifica la IU del permiso que se muestra al usuario.

Debes proporcionar una etiqueta y una descripción del permiso. Estos son recursos de cadenas que el usuario puede ver cuando consulta una lista de permisos (android:label) o detalles de un solo permiso (android:description). La etiqueta es corta: pocas palabras que describan la parte clave de funcionalidad que protege el permiso. La descripción incluye 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 el que la primera oración describe el permiso y la segunda 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 non-emergency
phone numbers without your intervention. Malicious apps may cause unexpected
calls on your phone bill.</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, querrás establecer esto en un grupo de sistema estándar (detallado 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

Puedes definir permisos personalizados para tus apps y solicitar permisos personalizados a otras apps definiendo elementos <uses-permission>. Sin embargo, evalúa con cuidado si es necesario hacerlo.

  • Si estás diseñando un paquete de apps que exponen funcionalidades entre sí, intenta diseñar 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. Aunque 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 verificaciones 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 cumplir la solicitud.

Si es necesario un permiso personalizado, piensa si deben acceder a él únicamente aplicaciones firmadas por el mismo desarrollador que la aplicación que realiza la verificación del permiso (como cuando se implementan comunicaciones entre procesos seguras entre dos aplicaciones del mismo desarrollador). En ese caso, te recomendamos usar permisos de firma. Los permisos de firma son transparentes para el usuario y evitan los permisos confirmados por el usuario, que pueden resultar confusos.

Continúa leyendo:

<uses-permission>
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
Análisis detallado del modelo de seguridad de la plataforma Android.