Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Security
Code

Llaves, Credenciales y Almacenamiento en Android

by
Difficulty:IntermediateLength:LongLanguages:

Spanish (Español) translation by James (you can also view the original English article)

En el post anterior sobre la seguridad de datos de usuario de Android, miramos en el cifrado de datos a través de un código de acceso suministrado por el usuario. Este tutorial desplazará el foco para credencial y almacenamiento de claves. Te comenzar introduciendo credenciales de la cuenta y terminar con un ejemplo de protección de datos utilizando la KeyStore.

A menudo, cuando se trabaja con un servicio de terceros, habrá alguna forma de autenticación requerido. Esto puede ser tan simple como un extremo /login que acepta un nombre de usuario y contraseña.

Al principio parece que una solución simple es crear una interfaz de usuario que solicita al usuario iniciar sesión y capturar y almacenar sus credenciales de inicio de sesión. Sin embargo, esto no es lo mejor porque nuestra aplicación no necesita saber las credenciales de una cuenta de terceros. En cambio, podemos utilizar el administrador de la cuenta, que delega el manejo de esa información sensible para nosotros.

Gerente de Cuentas

El administrador de cuentas es un ayudante centralizado para las credenciales de cuenta de usuario para que su aplicación no tiene que tratar directamente con las contraseñas. A menudo proporciona un token en lugar del verdadero usuario y contraseña que puede utilizar para hacer peticiones autenticadas a un servicio. Un ejemplo es cuando se solicita un token que usan OAuth2.

A veces, toda la información necesaria ya está almacenada en el dispositivo y otras veces el administrador de cuentas tendrá que llamar a un servidor para una muestra fresca. Usted pudo haber visto la sección de Cuentas en la configuración de su dispositivo para varias aplicaciones. Podemos obtener ese listado de cuentas disponibles como este:

El código requerirá el permiso de android.permission.GET_ACCOUNTS. Si usted está buscando una cuenta específica, usted puede encontrar como esta:

Una vez tengas la cuenta, un símbolo (token) de la cuenta se puede recuperar llamando al método getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler). El token puede utilizarse entonces para hacer solicitudes de API autenticadas a un servicio. Esto podría ser una API RESTful donde pasa en un parámetro token durante una solicitud HTTPS, sin tener que saber los datos del usuario cuenta privada.

Porque cada servicio tendrá una forma diferente de autenticación y el almacenamiento de las credenciales privadas, el administrador de cuentas proporciona módulos de autenticador a un servicio de terceros para implementar. Mientras que Android tiene implementaciones para muchos servicios populares, significa que usted puede escribir su propio autenticador para manejar el almacenamiento de autenticación y credenciales de cuenta de su aplicación. Esto le permite asegurarse de que las credenciales están encriptadas. Tenga en cuenta, esto también significa que las credenciales en el administrador de cuentas que son utilizadas por otros servicios se pueden almacenar en texto claro, haciéndolos accesibles a cualquier persona que se ha arraigado a su dispositivo.

En lugar de sencillas credenciales, hay veces cuando usted tendrá que lidiar con una clave o un certificado para un individuo o entidad, por ejemplo, cuando un tercero le envía un archivo de certificado que necesita mantener. El escenario más común es cuando una aplicación necesita para autenticar al servidor de una organización privada.

En el siguiente tutorial, buscará en el uso de certificados para la autenticación y comunicaciones seguras, pero todavía quiero abordar cómo almacenar estos elementos mientras tanto. La API de llavero fue construida originalmente para eso uso muy específico, instalar un par de certificado o clave privado de un archivo PKCS #12.

El Llavero

Introducido en Android 4.0 (API nivel 14), la API de llavero aborda la gestión de claves. Específicamente, se trabaja con objetos PrivateKey y X509Certificate y proporciona un contenedor más seguro que el uso de almacenamiento de datos de la aplicación. Eso es porque los permisos para las claves privadas permiten sólo para su propia aplicación de las claves de acceso y sólo después de la autorización de usuario. Esto significa que una pantalla de bloqueo debe configurar en el dispositivo antes de que usted puede hacer uso del almacenamiento de credenciales. También, los objetos en el llavero pueden obligarse al hardware seguro, si está disponible.

El código para instalar un certificado es como sigue:

El usuario se solicitará una contraseña para acceder a la clave privada y una opción para el nombre del certificado. Para recuperar la clave, el siguiente código presenta una interfaz de usuario que permite al usuario elegir en la lista de teclas instaladas.

Una vez hecha la elección, un nombre de alias de la cadena se devuelve en la devolución de llamada de alias(final String alias) donde se puede acceder directamente la cadena de certificado o clave privada.

Armados con ese conocimiento, ahora veamos cómo podemos utilizar el almacenamiento de credenciales para guardar datos confidenciales.

La KeyStore

En el tutorial anterior, vimos a la protección de datos a través de un código de acceso suministrado por el usuario. Este tipo de configuración es buena, pero los requisitos de la aplicación a menudo dirigen lejos de tener los usuarios iniciar sesión en cada momento y recordar una contraseña adicional.

Es donde se puede utilizar la API del almacén de claves. Desde entonces 1 de API, el almacén de claves se ha utilizado por el sistema para almacenar las credenciales VPN y WiFi. A partir de 4.3 (API 18), le permite trabajar con sus propias llaves asimétricas de aplicación específica, y en Android (API 23) puede almacenar una clave simétrica de AES. Así que mientras que el API no permite almacenar cuerdas sensibles directamente, estas teclas pueden almacenarse y luego utilizadas para cifrar cadenas.

El beneficio para almacenar una clave en el almacén de claves es que permite a las teclas para ser operados sin exponer el contenido secreto de esa clave; datos clave no entra en el espacio de aplicación. Recuerde que las claves están protegidas por permisos para que sólo su aplicación puede acceder a ellos, y pueden además ser seguros respaldado por el hardware Si el dispositivo es capaz. Esto crea un contenedor que hace más difícil extraer las claves de un dispositivo.

Generar una Nueva Clave al Azar

Para este ejemplo, en lugar de generar una clave de AES de un código de acceso suministrado por el usuario, nosotros podemos generar una clave aleatoria que se protegerán en el almacén de claves. Podemos hacer esto creando una instancia del KeyGenerator, establecida en el proveedor de "AndroidKeyStore".

Partes importantes que mirar aquí están las especificaciones de .setUserAuthenticationRequired(true) y .setUserAuthenticationValidityDurationSeconds(120). Estos requieren una pantalla de bloqueo para configurar y la clave para bloquearse hasta que el usuario se ha autenticado.

Mirando la documentación de .setUserAuthenticationValidityDurationSeconds(), verá que significa la clave sólo está disponible un cierto número de segundos de autenticación de contraseña y eso paso en -1 requiere la autenticación de huellas dactilares cada vez que quiera acceder a la clave. Habilitar el requisito de autenticación también tiene el efecto de revocar la clave cuando el usuario elimina o cambia la pantalla de bloqueo.

Porque almacenar una clave sin protección junto a los datos cifrados es como poner una llave de la casa bajo el felpudo, estas opciones intentan proteger la llave en reposo en caso de que un dispositivo está comprometido. Un ejemplo podría ser una descarga de datos sin conexión del dispositivo. Sin la contraseña de ser conocida por el dispositivo, que los datos se hace inútil.

La opción .setRandomizedEncryptionRequired(true) permite el requisito de que hay suficiente aleatorización (una nueva al azar IV cada vez) para que si los mismos datos se cifraron una segunda vez, esa salida cifrada todavía será diferente. Esto evita que un atacante obtener pistas sobre el texto cifrado basado en la alimentación de los mismos datos.

Otra opción a destacar es setUserAuthenticationValidWhileOnBody(boolean remainsValid), que bloquea la clave una vez que el dispositivo ha detectado ya no está en la persona.

Cifrar Datos

Ahora que la clave se almacena en el almacén de claves, podemos crear un método que cifra los datos mediante el objeto de cifrado, dado el SecretKey. Devuelve un HashMap que contiene los datos cifrados y un IV aleatorio que será necesario para descifrar los datos. Los datos cifrados, junto con el IV, pueden guardarse en un archivo o en las preferencias compartidas.

Descifrar a una Matriz de Bytes

Para descifrar, se aplica lo contrario. El objeto de Cipher se inicializa utilizando la constante DECRYPT_MODE, y se devuelve una matriz de byte[] descifrados.

Probando el Ejemplo

¡Ahora podemos probar nuestro ejemplo!

Uso de Claves Asimétricas RSA para Dispositivos Más Viejos 

Esta es una buena solución para almacenar los datos para las versiones M y más, pero lo que si su aplicación es compatible con versiones anteriores? Claves simétricas de AES no son compatibles bajo M, son claves asimétricas RSA. Eso significa que podemos usar claves RSA y cifrado para lograr lo mismo.

La principal diferencia aquí es que un par de claves asimétrica contiene dos claves, una privada y una clave pública, donde la clave pública cifra los datos y descifra la clave privada. Una KeyPairGeneratorSpec se pasa a la KeyPairGenerator que se inicializa con KEY_ALGORITHM_RSA y el proveedor de "AndroidKeyStore".

Para cifrar, obtener la RSAPublicKey del par de claves y utilizar con el objeto Cipher.

Decodificación se realiza mediante el objeto RSAPrivateKey.

Una cosa acerca de RSA es que la encriptación es más lenta de lo que es en AES. Esto es generalmente muy bien para pequeñas cantidades de información, como cuando usted está asegurando cadenas de preferencia compartidos. Si encuentras que hay un problema de rendimiento cifrar grandes cantidades de datos, sin embargo, puede en su lugar utilizar este ejemplo para cifrar y almacenar sólo una clave de AES. A continuación, utilice esa encriptación AES más rápida que se discutió en el tutorial anterior para el resto de sus datos. Puede generar una nueva clave AES y convertirla en una matriz de byte[] que es compatible con este ejemplo.

Para recuperar la clave de los bytes, haga lo siguiente:

¡Era un montón de código! Para mantener todos los ejemplos simples, he omitido exhaustiva de excepciones. Pero recuerde que su código de producción, se recomienda no simplemente todos casos Throwable en una captura declaración.

Conclusión

Esto completa el tutorial sobre las credenciales y claves. Gran parte de la confusión alrededor de las teclas y el almacenamiento tiene que ver con la evolución del sistema operativo Android, pero puede que la solución a utilizar dado el nivel de API su aplicación soporta.

Ahora que hemos cubierto las mejores prácticas para asegurar datos en reposo, el siguiente tutorial se centrará en la protección de datos en tránsito.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.