¿Cómo almacenar de forma segura token de acceso y secreto en Android?

123

Voy a usar oAuth para buscar correos y contactos de google. No quiero pedirle al usuario cada vez que inicie sesión para obtener un token de acceso y secreto. Por lo que entendí, necesito almacenarlos con mi aplicación en una base de datos o SharedPreferences. Pero estoy un poco preocupado por los aspectos de seguridad con eso. Leí que puedes cifrar y descifrar los tokens, pero es fácil para un atacante descompilar tu apk y clases y obtener la clave de cifrado.
¿Cuál es el mejor método para almacenar de forma segura estos tokens en Android?

si hombre
fuente
1
¿Cómo almaceno la clave y el secreto del consumidor (no puedo asegurarlos)? necesito que soliciten el token de acceso y el secreto ... ¿cómo lo hacen las otras aplicaciones existentes que usan oauth? hmm finalmente con oauth, debes ocuparte de muchos más problemas de seguridad para mí ... necesito mantener el token / secreto del consumidor de forma segura y también el token de acceso y el secreto ... finalmente no sería más simple solo almacena el nombre de usuario / contraseña del usuario encriptado? ... al final, ¿no es este último mejor? Todavía no puedo ver cómo oauth es mejor ...
hombre
¿me puede decir ... qué archivo almacena el token de acceso? Soy nuevo en Android e intenté ejecutar la aplicación Plus de muestra. Pero no encuentro esto en ninguna parte [método GoogleAuthUtil.getToken ().]
Abhishek Kaushik

Respuestas:

118

Almacénelos como preferencias compartidas . Esos son privados por defecto, y otras aplicaciones no pueden acceder a ellos. En dispositivos rooteados, si el usuario permite explícitamente el acceso a alguna aplicación que está tratando de leerlos, la aplicación puede usarlos, pero no puede protegerse contra eso. En cuanto al cifrado, debe solicitar al usuario que ingrese la frase de contraseña de descifrado cada vez (lo que anula el propósito de almacenar en caché las credenciales) o guardar la clave en un archivo, y obtendrá el mismo problema.

Hay algunos beneficios de almacenar tokens en lugar de la contraseña de nombre de usuario real:

  • Las aplicaciones de terceros no necesitan conocer la contraseña y el usuario puede estar seguro de que solo la envía al sitio original (Facebook, Twitter, Gmail, etc.)
  • Incluso si alguien roba un token, no puede ver la contraseña (que el usuario también podría estar usando en otros sitios)
  • Los tokens generalmente tienen una vida útil y caducan después de cierto tiempo
  • Las fichas se pueden revocar si sospecha que se han visto comprometidas
Nikolay Elenkov
fuente
1
Gracias por la respuesta! pero, ¿cómo puedo saber si mi clave de consumidor se ha visto comprometida? jajaja, será difícil decirlo ... ok sobre el almacenamiento del token de acceso y el secreto, ok, los guardo en preferencias compartidas y los cifro, pero ¿qué hay de la clave y el secreto del consumidor? No puedo almacenarlos en preferencias compartidas (en primer lugar, tendría que escribir explícitamente la clave y el secreto del consumidor en el código para guardarlo en preferencias compartidas) ... no sé si entiendes lo que quiero decir.
hombre
2
Debe colocarlo en la aplicación de una manera (algo) ofuscada, para que no sean visibles inmediatamente después de la descompilación, o usar su propia aplicación web de proxy de autenticación que tenga la clave y el secreto. Ponerlos en la aplicación es obviamente más fácil, y si crees que el riesgo de que alguien intente descifrar tu aplicación es lo suficientemente bajo, adopta ese enfoque. Por cierto, los puntos anteriores son para la contraseña del usuario. Si descubre que su clave / secreto de consumidor se ha visto comprometido, también puede revocarlos (eso, por supuesto, romperá su aplicación).
Nikolay Elenkov
1
@NikolayElenkov: Usted escribió 'En cuanto al cifrado, debe solicitar al usuario que ingrese la frase de contraseña de descifrado cada vez (lo que anula el propósito de almacenar en caché las credenciales), o guardar la clave en un archivo, y obtendrá el mismo problema'. . ¿Qué sucede si los crackers invierten su aplicación para obtener información sobre cómo funciona el cifrado? Su defensa puede estar rota. ¿Es una práctica recomendada almacenar dicha información (token, cifrado ...) utilizando código nativo?
anhldbk
1
Si se borran los datos de la aplicación, se pierde el token de actualización, que probablemente no sea lo que el usuario quería.
rds
1
¡Esta ya no es la mejor manera de almacenar tokens hoy en día!
Rahul Rastogi
19

Puede almacenarlos en AccountManager . Se considera la mejor práctica según estos tipos.

ingrese la descripción de la imagen aquí

Aquí está la definición oficial:

Esta clase proporciona acceso a un registro centralizado de las cuentas en línea del usuario. El usuario ingresa sus credenciales (nombre de usuario y contraseña) una vez por cuenta, otorgando a las aplicaciones acceso a recursos en línea con la aprobación de "un clic".

Para obtener una guía detallada sobre cómo usar AccountManager:

Sin embargo, al final AccountManager solo almacena su token como texto sin formato. Por lo tanto, sugeriría cifrar su secreto antes de almacenarlos en AccountManager. Puede utilizar varias bibliotecas de cifrado como AESCrypt o AESCrypto

Otra opción es usar la biblioteca Oculta . Es lo suficientemente seguro para Facebook y mucho más fácil de usar que AccountManager. Aquí hay un fragmento de código para guardar un archivo secreto usando Ocultar.

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
aldok
fuente
2
Buen consejo que ocultar. Parece muy fácil de usar. Y para muchos casos de uso.
lagos
No se pudo encontrar Ocultar a través del enlace. Puede estar desactivado
user1114
9

SharedPreferences no es una ubicación segura en sí misma. En un dispositivo rooteado, podemos leer y modificar fácilmente los xml de preferencias compartidas de todas las aplicaciones. Por lo tanto, los tokens deberían caducar con relativa frecuencia. Pero incluso si un token caduca cada hora, todavía se pueden robar tokens más nuevos de SharedPreferences. Android KeyStore se debe utilizar para el almacenamiento a largo plazo y la recuperación de claves criptográficas que se utilizarán para cifrar nuestros tokens para almacenarlos en, por ejemplo, SharedPreferences o una base de datos. Las claves no se almacenan dentro del proceso de una aplicación, por lo que es más difícil comprometerlas.

Entonces, más relevante que un lugar es cómo pueden ser seguros, por ejemplo, utilizando JWT de vida corta firmados criptográficamente, cifrándolos usando Android KeyStore y enviándolos con un protocolo seguro

apex39
fuente
9
Entonces, ¿dónde podemos almacenarlos?
Milind Mevada
3
  1. Desde el panel Proyecto de su Android Studio, seleccione "Archivos de proyecto" y cree un nuevo archivo llamado "keystore.properties" en el directorio raíz de su proyecto.

ingrese la descripción de la imagen aquí

  1. Abra el archivo "keystore.properties" y guarde su Token de acceso y secreto en el archivo.

ingrese la descripción de la imagen aquí

  1. Ahora carga la lea el token de acceso y secreto en su aplicación de módulo de build.gradle archivo. Luego debe definir la variable BuildConfig para su Token de acceso y Secreto para que pueda acceder directamente a ellos desde su código. Su build.gradle puede verse así:

    ... ... ... 
    
    android {
        compileSdkVersion 26
    
        // Load values from keystore.properties file
        def keystorePropertiesFile = rootProject.file("keystore.properties")
        def keystoreProperties = new Properties()
        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    
        defaultConfig {
            applicationId "com.yourdomain.appname"
            minSdkVersion 16
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            // Create BuildConfig variables
            buildConfigField "String", "ACCESS_TOKEN", keystoreProperties["ACCESS_TOKEN"]
            buildConfigField "String", "SECRET", keystoreProperties["SECRET"]
        }
    }
  2. Puede usar su Token de acceso y Secreto en su código de esta manera:

    String accessToken = BuildConfig.ACCESS_TOKEN;
    String secret = BuildConfig.SECRET;

De esta manera, no necesita almacenar el token de acceso y el secreto en texto plano dentro de su proyecto. Por lo tanto, incluso si alguien descompila su APK, nunca obtendrá su Token de acceso y Secreto mientras los carga desde un archivo externo.

Zahidur Rahman Faisal
fuente
1
Parece que no hay diferencia en la creación de un archivo de propiedades en lugar de codificación rígida.
Dzshean
Quiero escribir un token en tiempo de ejecución, ya que mi token cambia cada vez que abro mi aplicación.
Rehan Sarwar
1
Es una muy buena manera de almacenar algunos tokens como tokens de acceso API. Si desea almacenar credenciales de usuario, el NDK es una mejor manera.
Eric
66
¡No es así como debe almacenar información confidencial en su aplicación! Incluso si el repositorio no contiene los datos al usar este enfoque (los datos se inyectan en el proceso de compilación), esto genera un archivo BuildConfig que tiene el token / secreto en texto plano para que todos lo vean después de una simple descompilación.
Hrafn
-1

Bueno, puede asegurar su token de acceso siguiendo dos opciones.

  1. Utilice guardar su token de acceso en el almacén de claves de Android que no sería inverso.
  2. Use la función NDK con algunos cálculos que guarden su token y NDK con código c ++ que es muy difícil de revertir
M.Noman
fuente