Control de Permisos Android

Fecha de publicación:
Última actualización: 2021-12-31
Autor:

 

El control de permisos en las primeras versiones de Android consistía únicamente en declarar dichos permisos dentro de AndroidManifest.xml. Hoy en día se mantiene la misma modalidad para los permisos menos ofensivos. En cambio, los permisos más sensibles, como el acceso a la ubicación, requieren aprobación expresa de parte del usuario. Algunos permisos, como el envío de SMS, requieren aprobación selectiva por parte del equipo de Google Play para la publicación en línea. Además, los aplicativos firmados por el operador móvil tienen mayores privilegios. Esto se conoce como privilegios de operador y se usa para configurar el dispositivo (por ejemplo, los servicios de VoLTE). Los permisos pueden funcionar de manera temporal o permanente. Además, algunos permisos pueden funcionar de manera diferente si el servicio se encuentra en segundo plano.

Control de Permisos Android

 

Permisos de tiempo de instalación

Los permisos de tiempo de instalación, como su nombre lo indica, se otorgan en el momento de la instalación de la aplicación. Un ejemplo de permiso de tiempo de instalación es el permiso para acceder a internet.

Para hacer uso de un permiso de tiempo de instalación simplemente se debe declarar dicho permiso en AndroidManifest.xml, por ejemplo:

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

Estos permisos son visibles para el usuario en la tienda en línea. Sin embargo, muchas veces el usuario no presta atención a estos permisos durante la instalación de la app. Por eso, los permisos que se obtienen de esta manera tienen un nivel de impacto bajo desde el punto de vista de seguridad.

Los permisos de tiempo de instalación se adjudican de manera permanente.

 

Permisos de tiempo de ejecución

En cambio, los permisos más sensibles requieren acciones adicionales a la declaración dentro del XML. Un ejemplo son los permisos de localización:

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

El permiso ACCESS_COARSE_LOCATION aplica para las apps que requieren acceso a la localización aproximada del dispositivo. La localización aproximada generalmente se obtiene por medio de los servicios de red. En cambio, el permiso ACCESS_FINE_LOCATION se usa para obtener la localización precisa, la cual generalmente hace referencia a GPS. Google recomienda incluir ambos permisos para que el usuario pueda decidir si se aplica la localización aproximada o precisa, lo cual es posible a partir de Android 12.

Sin embargo, solamente declarar estos permisos no es suficiente. A partir de Android 6 se debe solicitar estos permisos en tiempo de ejecución. De esta manera el usuario tiene mayor conciencia de los permisos sensibles y puede no autorizarlos.

Google recomienda utilizar las clases auxiliares ContextCompat y ActivityCompat para validar y solicitar los permisos en tiempo de ejecución. Por ejemplo:

import androidx.core.content.ContextCompat;
import androidx.core.app.ActivityCompat;

String COARSE = "android.permission.ACCESS_COARSE_LOCATION";
String FINE = "android.permission.ACCESS_FINE_LOCATION";
int LOCRESULT = 123;

Context ctx = getApplicationContext();
if(ContextCompat.checkSelfPermission(ctx, FINE) != 0 &&
   ContextCompat.checkSelfPermission(ctx, COARSE) != 0){
   ActivityCompat.requestPermissions(this,
      new String[]{ FINE }, LOCRESULT);
}
 

Este código verifica si alguno de estos 2 permisos ya se encuentra aprobado. En caso contrario se despliega un cuadro solicitando que el usuario conceda los permisos. Nótese que la verificación de permisos se realiza sobre el contexto asociado con el proceso, en el cual se está ejecutando la aplicación. Esto es porque internamente Android asocia los permisos con el ID de proceso (PID) y el ID de usuario (UID). En cambio, la solicitud de permisos recibe un parámetro que representa la actividad (Activity) actual, ya que puede desplegar un elemento interactivo para que el usuario apruebe la solicitud. Cuando el usuario apruebe o desapruebe la solicitud de permisos, se invocará el método onRequestPermissionsResult sobre esta misma actividad:

@Override
public void onRequestPermissionsResult(
   int req, String perms[], int[] res){
   if(req == LOCRESULT
      && res.length > 0 && res[0] == 0){
      // permisos concedidos
   }
}
 

Es opcional procesar la notificación del resultado. La aprobación se realiza de manera asíncrona. Por lo tanto, procesar la notificación permite implementar una lógica condicional según la decisión del usuario. Por ejemplo, si el usuario decide no aprobar los permisos, la aplicación podría desplegar un mensaje de error o implementar una funcionalidad alterna.

Si no desea utilizar librerías auxiliares AndroidX (Android Extension Library), es posible implementar la misma lógica por medio de las API estándar de Android. Esta opción no es recomendada por Google y podría dejar de funcionar en alguna versión futura de Android.

import android.os.Process;
import android.app.Activity;

String COARSE = "android.permission.ACCESS_COARSE_LOCATION";
String FINE = "android.permission.ACCESS_FINE_LOCATION";
int LOCRESULT = 123;

int pid = Process.myPid(), uid = Process.myUid();
if(checkPermission(FINE, pid, uid) != 0 &&
   checkPermission(COARSE, pid, uid) != 0){
      requestPermissions(new String[]{ FINE }, LOCRESULT);
}
 

En ambos casos es importante agregar la verificación de versión de SDK y un manejo mínimo de errores con un bloque try/catch, como sigue:

if(Build.VERSION.SDK_INT > 22){
   try{
     // verificar permisos de localización
   }catch(Exception exc){
      Log.e("App", "exception", exc);
   }
}
 

De esta manera, el código de validación de permisos se ejecuta solamente en Android 6 o posterior (SDK mayor que 22), ya que en versiones anteriores estos permisos eran otorgados en tiempo de instalación.

Recuerde que a partir de Android 12 se recomienda separar los permisos de localización aproximada y localización precisa para que el usuario pueda elegir uno de los 2 métodos, ambos o ninguno.

Para habilitar otros permisos de tiempo de ejecución se utiliza la misma metodología. Previo a la solicitud de los permisos, se recomienda desplegar un cuadro informativo explicando por qué se requieren dichos permisos. Esto ayuda a convencer al usuario para que no bloquee los permisos.

Los permisos de tiempo de ejecución pueden ser revocados automáticamente, luego de un período de inactividad. Esto sucede a partir de Android 11. Si la app deja de utilizarse durante un tiempo largo (varios meses), los permisos pueden ser revocados automáticamente. Por lo tanto, la aplicación debe verificar los permisos cada vez que los va a utilizar.

 

Privilegios de operador

A partir de Android 5.1 se introdujo una funcionalidad conocida como privilegios de operador (en inglés, Carrier Privileges). Esta funcionalidad permite otorgar permisos especiales para las aplicaciones cuya firma digital concuerda con la lista de firmas instaladas en la SIMcard. Se asume que solamente el operador móvil o el fabricante de la SIMcard pueden modificar la lista de firmas en la SIMcard. Un proveedor de aplicaciones independiente no tiene acceso a las llaves administrativas de la SIMcard. Por lo tanto, no puede manipular la lista de firmas.

Lo que se almacena en la SIMcard es un valor hash (SHA1) de la clave, no la clave misma. Opcionalmente, junto con este hash, se puede incluir el nombre del paquete de la aplicación, correspondiente al parámetro package dentro de AndroidManifest.xml. Esto puede ser útil si la misma firma se usa en múltiples aplicaciones, pero los privilegios de operador son requeridos solamente en algunas.

Existen 2 métodos para almacenar la lista de firmas en la SIMcard:

  • Por medio de un aplicativo llamado ARA, el cual se ejecuta dentro de la SIMcard. Este aplicativo se encuentra definido en el estándar GPD_SPE_013.1
  • Dentro de un archivo llamado ARF definido en el estándar PKCS #15.2

ARF es soportado a partir de Android 7 y se usa si no se encuentra ARA. Dado que ARA tiene prioridad y es soportado a partir de Android 5.1, este método es más usado que ARF.

Actualmente la gran mayoría de las SIMcard soportan los estándares Global Platform. Esto no garantiza que el aplicativo ARA se encuentre disponible en todas las SIMcard, ya que no todos los operadores hacen uso de esta funcionalidad. Una versión de ARA de código abierto se puede encontrar aquí:

GitHub
El aplicativo ARA-M de Bertrand Martel es gratuito y compatible con la mayoría de las SIMcard.

 

Los operadores móviles acostumbran utilizar versiones de ARA suministradas por los fabricantes de SIMcard. Una de las razones es que los aplicativos genéricos pueden ocasionar uso intensivo de la memoria no volátil de la SIMcard, lo cual acorta su vida útil.

GitHub
El proyecto CoIMS contiene una guía para instalar ARA-M. Además, incluye consejos para depurar errores comunes.

 

Para instalar un aplicativo en la SIMcard se debe contar con las llaves administrativas. El dilema está en que las SIMcard de pruebas, las cuales se comercializan para propósitos de ingeniería e incluyen llaves administrativas, generalmente no incluyen suscripción móvil. En cambio, las SIMcard que ofrecen los operadores móviles no incluyen llaves administrativas. Por lo tanto, las posibilidades de utilizar esta tecnología con una suscripción móvil real son limitadas. Generalmente se requiere una cooperación estrecha con el operador móvil para lograr aprovisionar las firmas del desarrollador en las SIMcard de los usuarios móviles.

A continuación se presenta la lista con algunas funcionalidades disponibles bajo privilegios de operador:

  • Obtener el ID de la suscripción móvil (IMSI).
  • Cambiar el nombre del operador.
  • Activar/desactivar las redes LTE, CDMA, GSM/WCDMA, etc.
  • Modificar la configuración de IMS (ej: VoLTE, VoWiFi).

Una lista más completa puede ser consultada en el sitio oficial de Android para desarrolladores, aunque la lista exhaustiva no es pública. Los privilegios de operador también abarcan los permisos sensibles de tiempo de ejecución, como los permisos para activar o desactivar servicios de datos, bloquear redes, seleccionar la red móvil actual de manera manual o automática, intercambiar comandos APDU con la SIMcard, etc. En el siguiente artículo profundizaremos en este último caso de uso.

Dentro de la app Android no se requiere ningún código adicional para hacer uso de los privilegios de operador. Estos privilegios son otorgados automáticamente si la SIMcard contiene el hash de la llave, con la cual se encuentra firmada la app, y opcionalmente el nombre del paquete de la app. Los privilegios también se revocan automáticamente si la SIMcard es removida.

Los privilegios de operador funcionan aun sin registro en la red móvil. También funcionan en modo avión. Si el teléfono soporta dual-SIM o multi-SIM, Android intenta escanear las firmas de ARA o ARF en todas las SIMcard disponibles.

 

Conclusiones

El manejo de permisos Android ha evolucionado y se ha vuelto cada vez más restrictivo. Aunque Android es un sistema operativo abierto, no todos los aspectos en el manejo de los permisos son públicos y están documentados.

Si tiene la necesidad de utilizar permisos sensibles y no puede obtener dichos permisos para la versión de Android más actual, es posible que en una versión más antigua la obtención de los mismos permisos sea menos restrictiva. Por ejemplo, la lectura del ID de la suscripción (IMSI) en Android 1.6 se podía hacer simplemente declarando el permiso READ_PHONE_STATE dentro del archivo AndroidManifest.xml.

Si está desarrollando una aplicación de uso masivo, es importante reducir el uso de permisos, especialmente los permisos sensibles. No hacerlo incrementa los riesgos de seguridad, por lo que también afecta la permanencia de la aplicación en las tiendas en línea como Google Play.

 

Referencias

  1. «Secure Element Access Control v1.1» (en inglés), Global Platform (2014)
  2. «Cryptographic Token Information Format Standard v1.1» (en inglés), RSA Laboratories (1999)