que programa para keeper guardar den cuenta contraseñas celular app aplicacion administrador android reverse-engineering proguard api-key

android - programa - Mejores prácticas para almacenar y proteger claves de API privadas en aplicaciones



keeper (14)

La clave de App-Secret debe mantenerse privada, pero cuando se lanza la aplicación, algunos pueden revertirla.

para esos tipos no se ocultará, bloquee el código ProGuard . Es un refactor y algunos ofuscadores pagados están insertando algunos operadores bit a bit para recuperar la cadena jk433g34hg3 . Puedes hacer de 5 a 15 minutos más el pirateo si trabajas 3 días :)

La mejor manera es mantenerlo como está, imho.

Incluso si almacena en el lado del servidor (su PC), la clave puede ser hackeada e impresa. Tal vez esto lleva más tiempo? De todos modos, es una cuestión de pocos minutos o unas pocas horas en el mejor de los casos.

Un usuario normal no descompilará su código.

La mayoría de los desarrolladores de aplicaciones integrarán algunas bibliotecas de terceros en sus aplicaciones. Si es para acceder a un servicio, como Dropbox o YouTube, o para el registro de bloqueos. El número de bibliotecas y servicios de terceros es asombroso. La mayoría de esas bibliotecas y servicios se integran mediante la autenticación de alguna manera con el servicio, la mayoría de las veces, esto sucede a través de una clave API. Por motivos de seguridad, los servicios generalmente generan una clave pública y privada, a menudo también denominada secreta. Desafortunadamente, para conectarse a los servicios, esta clave privada se debe utilizar para autenticar y, por lo tanto, probablemente sea parte de la aplicación. No hace falta decir que esto se enfrenta a un inmenso problema de seguridad. Las claves API públicas y privadas se pueden extraer de los APK en cuestión de minutos y se pueden automatizar fácilmente.

Suponiendo que tengo algo similar a esto, ¿cómo puedo proteger la clave secreta?

public class DropboxService { private final static String APP_KEY = "jk433g34hg3"; private final static String APP_SECRET = "987dwdqwdqw90"; private final static AccessType ACCESS_TYPE = AccessType.DROPBOX; // SOME MORE CODE HERE }

¿Cuál es, en su opinión, la mejor y más segura manera de almacenar la clave privada? Ofuscación, encriptación, ¿qué te parece?


Siga 3 pasos simples para asegurar la clave API / Secreto

Podemos usar Gradle para asegurar la clave API o la clave secreta.

1. gradle.properties (propiedades del proyecto): Crear variable con clave.

GoolgeAPIKey = "Your API/Secret Key"

2. build.gradle (Module: app): establece la variable en build.gradle para acceder a ella en la actividad o el fragmento. Agregue el siguiente código a buildTypes {}.

buildTypes.each { it.buildConfigField ''String'', ''GoogleSecAPIKEY'', GoolgeAPIKey }

3. Acceda a él en Activity / Fragment por BuildConfig de la aplicación:

BuildConfig.GoogleSecAPIKEY

Actualización:

La solución anterior es útil en el proyecto de código abierto para comprometerse con Git. (Gracias a David Rawson y riyaz-ali por tu comentario).

Según los comentarios de Matthew y Pablo Cegarra, la forma anterior no es segura y Decompiler permitirá que alguien vea el BuildConfig con nuestras claves secretas.

Solución:

Podemos usar NDK para proteger las claves de API. Podemos almacenar claves en la clase C / C ++ nativa y acceder a ellas en nuestras clases de Java.

Por favor siga this blog para asegurar las claves API usando NDK.

Un seguimiento de cómo almacenar tokens de forma segura en Android


  1. Tal como está, su aplicación compilada contiene las cadenas de clave, pero también los nombres constantes APP_KEY y APP_SECRET. Extraer claves de dicho código de autodocumentación es trivial, por ejemplo con la herramienta estándar de Android dx.

  2. Puede aplicar ProGuard. Dejará intactas las cadenas de teclas, pero eliminará los nombres constantes. También cambiará el nombre de clases y métodos con nombres cortos y sin significado, siempre que sea posible. Extraer las claves toma más tiempo para determinar qué cadena sirve para qué propósito.

    Tenga en cuenta que configurar ProGuard no debería ser tan difícil como teme. Para empezar, solo necesita habilitar ProGuard, como se documenta en project.properties. Si hay algún problema con las bibliotecas de terceros, es posible que deba suprimir algunas advertencias y / o evitar que se confundan, en proguard-project.txt. Por ejemplo:

    -dontwarn com.dropbox.** -keep class com.dropbox.** { *; }

    Este es un enfoque de fuerza bruta; puede refinar dicha configuración una vez que la aplicación procesada funcione.

  3. Puede ofuscar las cadenas manualmente en su código, por ejemplo con una codificación Base64 o preferiblemente con algo más complicado; tal vez incluso código nativo. Un pirata informático tendrá que aplicar ingeniería inversa estática a su codificación o interceptar dinámicamente la decodificación en el lugar adecuado.

  4. Puede aplicar un ofuscador comercial, como DexGuard hermano especializado de DexGuard . Además, puede cifrar / ofuscar las cadenas y las clases para usted. Extraer las claves requiere más tiempo y experiencia.

  5. Es posible que pueda ejecutar partes de su aplicación en su propio servidor. Si puedes guardar las llaves allí, son seguras.

Al final, es una compensación económica que debe hacer: qué tan importantes son las claves, cuánto tiempo o software puede pagar, qué sofisticados son los piratas informáticos interesados ​​en las claves, cuánto tiempo querrán. gastar, cuánto vale una demora antes de que se pirateen las claves, a qué escala los piratas informáticos exitosos distribuirán las claves, etc. Las pequeñas piezas de información como las claves son más difíciles de proteger que las aplicaciones completas. Intrínsecamente, nada en el lado del cliente es inquebrantable, pero ciertamente puedes subir el listón.

(Soy el desarrollador de ProGuard y DexGuard)


¡Otro enfoque es no tener el secreto en el dispositivo en primer lugar! Ver hackernoon.com/mobile-api-security-techniques-682a5da4fe10 (especialmente la parte 3).

Usando la tradición de indirección respetada en el tiempo, comparta el secreto entre su punto final de API y un servicio de autenticación de aplicaciones. Cuando su cliente desea realizar una llamada a la API, le pide al servicio de autenticación de la aplicación que lo autentique (utilizando técnicas de certificación remota sólidas) y recibe un token de tiempo limitado (generalmente JWT) firmado por el secreto. El token se envía con cada llamada a la API donde el punto final puede verificar su firma antes de actuar en la solicitud.

El secreto real nunca está presente en el dispositivo; de hecho, la aplicación nunca tiene idea de si es válida o no, sino que solicita la autenticación y pasa el token resultante. Como buen beneficio de la indirección, si alguna vez desea cambiar el secreto, puede hacerlo sin requerir que los usuarios actualicen sus aplicaciones instaladas.

Entonces, si quieres proteger tu secreto, no tenerlo en tu aplicación es una buena manera de hacerlo.


Basado en la experiencia amarga, y después de consultar con un experto en IDA-Pro, la mejor solución es mover una parte clave del código a un DLL / SharedObject, luego recuperarlo de un servidor y cargarlo en tiempo de ejecución.

Los datos confidenciales deben codificarse ya que es muy fácil hacer algo como esto:

$ strings libsecretlib.so | grep My My_S3cr3t_P@$$W0rD


Edad antigua puesto, pero sigue siendo lo suficientemente bueno. Creo que ocultarlo en una biblioteca .so sería genial, usando NDK y C ++, por supuesto. Los archivos .so se pueden ver en un editor hexadecimal, pero buena suerte al descompilar eso: P


Este ejemplo tiene varios aspectos diferentes. Mencionaré un par de puntos que creo que no se han cubierto explícitamente en otros lugares.

Protegiendo el secreto en tránsito.

Lo primero que debe tener en cuenta es que para acceder a la API de Dropbox mediante el mecanismo de autenticación de su aplicación es necesario que transmita su clave y su secreto. La conexión es HTTPS, lo que significa que no puede interceptar el tráfico sin conocer el certificado TLS. Esto es para evitar que una persona intercepte y lea los paquetes en su viaje desde el dispositivo móvil al servidor. Para los usuarios normales, es una forma realmente buena de garantizar la privacidad de su tráfico.

Lo que no es bueno es evitar que una persona maliciosa descargue la aplicación e inspeccione el tráfico. Es realmente fácil usar un proxy de hombre en el medio para todo el tráfico que entra y sale de un dispositivo móvil. No se requeriría desmontaje ni ingeniería inversa de código para extraer la clave de la aplicación y el secreto en este caso debido a la naturaleza de la API de Dropbox.

Podría hacer la pinning que compruebe que el certificado TLS que recibe del servidor es el que espera. Esto agrega una verificación al cliente y hace que sea más difícil interceptar el tráfico. Esto haría que sea más difícil inspeccionar el tráfico en vuelo, pero la verificación de fijación se realiza en el cliente, por lo que probablemente todavía sea posible desactivar la prueba de fijación. Aunque lo hace más difícil.

Protegiendo el secreto en reposo.

Como primer paso, usar algo como proguard ayudará a que sea menos obvio dónde se guardan los secretos. También puede usar el NDK para almacenar la clave y el secreto y enviar solicitudes directamente, lo que reduciría considerablemente el número de personas con las habilidades adecuadas para extraer la información. Se puede lograr una ofuscación adicional al no almacenar los valores directamente en la memoria durante un período de tiempo prolongado, puede cifrarlos y descifrarlos justo antes de usarlos como lo sugiere otra respuesta.

Opciones más avanzadas

Si ahora está paranoico acerca de poner el secreto en cualquier lugar de su aplicación y tiene tiempo y dinero para invertir en soluciones más completas, entonces podría considerar almacenar las credenciales en sus servidores (suponiendo que tenga alguna). Esto aumentaría la latencia de cualquier llamada a la API, ya que tendrá que comunicarse a través de su servidor y podría aumentar los costos de ejecución de su servicio debido al aumento en el rendimiento de datos.

Luego, debe decidir cuál es la mejor manera de comunicarse con sus servidores para asegurarse de que estén protegidos. Esto es importante para evitar que vuelvan a surgir los mismos problemas con su API interna. La mejor regla de oro que puedo dar es no transmitir ningún secreto directamente debido a la amenaza del hombre en el medio. En su lugar, puede firmar el tráfico utilizando su secreto y verificar la integridad de cualquier solicitud que llegue a su servidor. Una forma estándar de hacer esto es calcular un HMAC del mensaje ingresado en un secreto. Trabajo en una empresa que tiene un producto de seguridad que también opera en este campo, por lo que me interesan este tipo de cosas. De hecho, aquí hay un artículo de blog de uno de mis colegas que repasa la mayor parte de esto.

¿Cuánto debo hacer?

Con cualquier consejo de seguridad como este, debe tomar una decisión de costo / beneficio acerca de lo difícil que es hacerlo para que alguien ingrese. Si usted es un banco que protege a millones de clientes, su presupuesto es totalmente diferente al de alguien que apoya una aplicación en su cuenta. tiempo libre. Es prácticamente imposible evitar que alguien rompa tu seguridad, pero en la práctica pocas personas necesitan todas las campanas y silbidos y con algunas precauciones básicas puedes llegar lejos.


La única forma verdadera de mantener estos datos privados es mantenerlos en su servidor y hacer que la aplicación envíe lo que sea al servidor, y el servidor interactúe con Dropbox. De esa manera NUNCA distribuyas tu clave privada en ningún formato.


La solución más segura es mantener sus claves en un servidor y dirigir todas las solicitudes que necesiten esa clave a través de su servidor. De esa manera, la clave nunca abandona su servidor, por lo que siempre que su servidor esté seguro, también lo será su clave. Por supuesto, hay un costo de rendimiento con esta solución.


Lo que sea que haga para asegurar sus claves secretas no será una solución real. Si el desarrollador puede descompilar la aplicación, no hay forma de asegurar la clave, ocultar la clave es solo seguridad por oscuridad y también la ofuscación del código. El problema con la seguridad de una clave secreta es que para asegurarla debe usar otra clave y esa clave también debe estar protegida. Piense en una clave oculta en una caja que está bloqueada con una clave. Coloca una caja dentro de una habitación y cierra la habitación. Te quedan con otra llave para asegurar. Y esa clave aún estará codificada en su aplicación.

Entonces, a menos que el usuario ingrese un PIN o una frase, no hay forma de ocultar la clave. Pero para hacer eso tendría que tener un esquema para administrar PINs fuera de banda, lo que significa que a través de un canal diferente. Ciertamente no es práctico para asegurar claves para servicios como las API de Google.


Mantenga el secreto en la firebase database y obtenga de él cuando se inicie la aplicación. Es mucho mejor que llamar a un servicio web.


Pocas ideas, en mi opinión solo la primera da alguna garantía:

  1. Guarde sus secretos en algún servidor en Internet y, cuando sea necesario, simplemente tómelos y úselos. Si el usuario está a punto de usar Dropbox, nada le impide hacer una solicitud a su sitio y obtener su clave secreta.

  2. Ponga sus secretos en el código jni, agregue un código variable para hacer que sus bibliotecas sean más grandes y más difíciles de descompilar. También puede dividir la cadena clave en algunas partes y mantenerla en varios lugares.

  3. use ofuscador, también póngalo en el código secreto de hash y luego descúbralo cuando sea necesario.

  4. Ponga su clave secreta como últimos píxeles de una de sus imágenes en activos. Luego, cuando sea necesario, léelo en tu código. La ofuscación de su código debería ayudar a ocultar el código que lo leerá.

Si quieres echar un vistazo rápido a lo fácil que es leer tu código apk, entonces toma APKAnalyser:

http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/


Se puede agregar a la solución @Redman, la base de datos de base de fuego o RemoteConfig (con el valor predeterminado nulo):

  1. Cifra tus llaves
  2. Guárdalo en la base de datos de base de fuego.
  3. Obténgalo durante el inicio de la aplicación o cuando sea necesario
  4. descifrar claves y usarlas

¿Qué es diferente en esta solución?

  • sin credenciales para base de fuego
  • El acceso a Firebase está protegido, por lo que solo las aplicaciones con certificado firmado tienen privilegios para realizar llamadas API
  • cifrar / descifrar para evitar la intercepción del hombre medio. Sin embargo las llamadas ya https a firebase

Una posible solución es codificar los datos en su aplicación y usar la decodificación en tiempo de ejecución (cuando desee usar esos datos). También recomiendo usar progaurd para que sea difícil de leer y entender el código fuente descompilado de su aplicación. por ejemplo, puse una clave codificada en la aplicación y luego usé un método de decodificación en mi aplicación para descodificar mis claves secretas en tiempo de ejecución:

// "the real string is: "mypassword" "; //encoded 2 times with an algorithm or you can encode with other algorithms too public String getClientSecret() { return Utils.decode(Utils .decode("Ylhsd1lYTnpkMjl5WkE9PQ==")); }

El código fuente descompilado de una aplicación programada es este:

public String c() { return com.myrpoject.mypackage.g.h.a(com.myrpoject.mypackage.g.h.a("Ylhsd1lYTnpkMjl5WkE9PQ==")); }

Al menos es lo suficientemente complicado para mí. Esto es lo que hago cuando no tengo más remedio que almacenar un valor en mi aplicación. Por supuesto que todos sabemos que no es la mejor manera pero funciona para mí.

/** * @param input * @return decoded string */ public static String decode(String input) { // Receiving side String text = ""; try { byte[] data = Decoder.decode(input); text = new String(data, "UTF-8"); return text; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return "Error"; }

Versión descompilada:

public static String a(String paramString) { try { str = new String(a.a(paramString), "UTF-8"); return str; } catch (UnsupportedEncodingException localUnsupportedEncodingException) { while (true) { localUnsupportedEncodingException.printStackTrace(); String str = "Error"; } } }

y puedes encontrar tantas clases de encriptadores con una pequeña búsqueda en google.