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 registrar fallas. El número de bibliotecas y servicios de terceros es asombroso. La mayoría de esas bibliotecas y servicios se integran de alguna manera autenticándose con el servicio, la mayoría de las veces, esto sucede a través de una clave API. Por motivos de seguridad, los servicios suelen generar una clave pública y privada, a menudo también denominada clave secreta. Desafortunadamente, para conectarse a los servicios, esta clave privada debe usarse para autenticarse 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 forma de almacenar la clave privada? Ofuscación, encriptación, ¿qué te parece?
fuente
Respuestas:
Tal como está, su aplicación compilada contiene las cadenas de teclas, pero también los nombres constantes APP_KEY y APP_SECRET. Extraer claves de dicho código autodocumentado es trivial, por ejemplo, con la herramienta estándar de Android dx.
Puede aplicar ProGuard. Dejará las cadenas de teclas intactas, pero eliminará los nombres constantes. También cambiará el nombre de las clases y métodos con nombres cortos y sin sentido, siempre que sea posible. Luego, extraer las claves lleva 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 ofusquen, en proguard-project.txt. Por ejemplo:
Este es un enfoque de fuerza bruta; puede refinar dicha configuración una vez que la aplicación procesada funcione.
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 realizar una ingeniería inversa estática de su codificación o interceptar dinámicamente la decodificación en el lugar adecuado.
Puede aplicar un ofuscador comercial, como el hermano especializado de ProGuard, DexGuard . Además, puede encriptar / ofuscar las cadenas y clases por usted. Extraer las claves requiere más tiempo y experiencia.
Es posible que pueda ejecutar partes de su aplicación en su propio servidor. Si puede mantener las llaves allí, están a salvo.
Al final, es una compensación económica que debes hacer: cuán importantes son las claves, cuánto tiempo o software puedes permitirte, cuán sofisticados son los hackers que están interesados en las claves, cuánto tiempo querrán gastar, cuánto vale una demora antes de que las claves sean pirateadas, en qué escala los hackers exitosos distribuirán las claves, etc. Pequeñas piezas de información como las claves son más difíciles de proteger que las aplicaciones completas. Intrínsecamente, nada del lado del cliente es irrompible, pero ciertamente puede elevar el listón.
(Soy el desarrollador de ProGuard y DexGuard)
fuente
Pocas ideas, en mi opinión solo la primera da alguna garantía:
Guarde sus secretos en algún servidor de Internet y, cuando sea necesario, simplemente cómprelos 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.
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 de teclas en pocas partes y mantenerlas en varios lugares.
use ofuscador, también ponga en secreto el código hash y luego deshágalo cuando sea necesario.
Ponga su clave secreta como últimos píxeles de una de sus imágenes en activos. Luego, cuando sea necesario, léalo en su código. Ofuscar 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, toma APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
fuente
¡Otro enfoque es no tener el secreto en el dispositivo en primer lugar! Ver técnicas de seguridad de API móvil (especialmente la parte 3).
Utilizando la tradicional tradición de indirección, comparta el secreto entre su punto final API y un servicio de autenticación de aplicaciones.
Cuando su cliente quiere hacer una llamada a la API , le pide al servicio de autenticación de la aplicación que la autentique (usando técnicas de certificación remota fuertes) y recibe un tiempo limitado (generalmente JWT token de ) 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 sobre 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, solo solicita la autenticación y pasa el token resultante. Como un 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 desea proteger su secreto, no tenerlo en su aplicación en primer lugar es una buena manera de hacerlo.
fuente
Antigua forma no segura:
Siga 3 pasos simples para asegurar API / clave secreta ( Respuesta anterior )
Podemos usar Gradle para asegurar la clave API o la clave secreta.
1. gradle.properties (Propiedades del proyecto): Crear variable con clave.
2. build.gradle (Módulo: aplicación): establezca la variable en build.gradle para acceder a ella en actividad o fragmento. Agregue el siguiente código a buildTypes {}.
3. Acceda a él en Actividad / Fragmento mediante BuildConfig de la aplicación:
Actualización:
La solución anterior es útil en el proyecto de código abierto para comprometerse sobre 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 nativa C / C ++ y acceder a ellas en nuestras clases Java.
Siga este blog para proteger las claves de API con NDK.
Un seguimiento sobre cómo almacenar tokens de forma segura en Android
fuente
gradle.properties
no debería registrarse en Git, por lo que esta es una forma de mantener el secreto fuera del código fuente comprometido, al menosapk
(se agregará alBuildConfig
archivo generado ), aunque definitivamente es una buena idea administrar diferentes claves API (por ejemplo, en un proyecto de código abierto)BuildConfig.java
archivo tendrá la clave en forma de texto sin formato. Esto no es mejor de lo que el OP ya está haciendo.para esos tipos no se esconderá, bloquee
ProGuard
el código. Es un refactor y algunos ofuscadores pagados están insertando algunos operadores bit a bit para recuperar eljk433g34hg3
cadena. Puedes alargar de 5 a 15 minutos el pirateo si trabajas 3 días :)La mejor manera es mantenerlo como está, en mi humilde opinión.
Incluso si almacena en el lado del servidor (su PC), la clave se puede piratear e imprimir. Tal vez esto lleva más tiempo? De todos modos, es cuestión de unos minutos o unas pocas horas en el mejor de los casos.
Un usuario normal no descompilará su código.
fuente
Una posible solución es codificar los datos en su aplicación y usar la decodificación en tiempo de ejecución (cuando quiera usar esos datos). También recomiendo usar progaurd para dificultar la lectura y la comprensión del 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 decodificar mis claves secretas en tiempo de ejecución:
El código fuente descompilado de una aplicación protegida es este:
Al menos es lo suficientemente complicado para mí. esta es la forma en que lo hago cuando no tengo más remedio que almacenar un valor en mi aplicación. Por supuesto, todos sabemos que no es la mejor manera, pero funciona para mí.
Versión descompilada:
y puedes encontrar tantas clases de encriptadores con una pequeña búsqueda en google.
fuente
Al agregar a la solución @Manohar Reddy, se puede usar Firebase Database o firebase RemoteConfig (con valor predeterminado nulo):
¿Qué es diferente en esta solución?
fuente
Este ejemplo tiene varios aspectos diferentes. Mencionaré un par de puntos que no creo que hayan sido cubiertos explícitamente en otra parte.
Protegiendo el secreto en tránsito
Lo primero que debe tener en cuenta es que para acceder a la API de Dropbox utilizando su mecanismo de autenticación de la aplicación , debe transmitir su clave y 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 muy buena manera de garantizar la privacidad de su tráfico.
Lo que no es bueno es evitar que una persona malintencionada descargue la aplicación e inspeccione el tráfico. Es realmente fácil usar un proxy man-in-the-middle para todo el tráfico que entra y sale de un dispositivo móvil. No requeriría desmontaje ni ingeniería inversa del código para extraer la clave y el secreto de la aplicación en este caso debido a la naturaleza de la API de Dropbox.
Puede hacer una fijación que verifica que el certificado TLS que recibe del servidor es el que espera. Esto agrega un cheque al cliente y hace que sea más difícil interceptar el tráfico. Esto dificultaría la inspección del tráfico en vuelo, pero la verificación de anclaje se realiza en el cliente, por lo que probablemente todavía sea posible desactivar la prueba de anclaje. Sin embargo, 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 podría usar el NDK para almacenar la clave y el secreto y enviar solicitudes directamente, lo que reduciría en gran medida el número de personas con las habilidades adecuadas para extraer la información. Se puede lograr una mayor ofuscación 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 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 ejecutar su servicio debido a un mayor 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 general 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 con su secreto y verificar la integridad de cualquier solicitud que llegue a su servidor. Una forma estándar de hacerlo es calcular un HMAC del mensaje codificado en un secreto. Trabajo en una empresa que tiene un producto de seguridad que también opera en este campo, por lo que este tipo de cosas me interesan. 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 sobre cuán difícil quiere que sea una persona que ingrese. Si usted es un banco que protege a millones de clientes, su presupuesto es totalmente diferente a alguien que respalda una aplicación tiempo libre. Es prácticamente imposible evitar que alguien rompa su seguridad, pero en la práctica pocas personas necesitan todas las campanas y silbatos y con algunas precauciones básicas puede llegar lejos.
fuente
La solución más segura es mantener sus claves en un servidor y enrutar todas las solicitudes que necesitan 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, su clave también. Por supuesto, hay un costo de rendimiento con esta solución.
fuente
Guarde el secreto
firebase database
y descúbralo cuando se inicie la aplicación. Es mucho mejor que llamar a un servicio web.fuente
Cualquier cosa 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 lo es la ofuscación del código. El problema con la seguridad de una clave secreta es que para protegerla debe usar otra clave y esa clave también debe asegurarse. Piense en una llave escondida en una caja que está bloqueada con una llave. Colocas una caja dentro de una habitación y la cierras. Te queda otra llave para asegurar. Y esa clave aún estará codificada dentro de 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 los PIN que ocurren fuera de banda, lo que significa a través de un canal diferente. Ciertamente, no es práctico para asegurar claves para servicios como las API de Google.
fuente
Edad antigua publicación, pero todavía lo suficientemente bueno. Creo que esconderlo 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 descompilando eso: P
fuente
La única forma verdadera de mantener estos privados es mantenerlos en su servidor, y hacer que la aplicación envíe lo que sea al servidor, y el servidor interactúa con Dropbox. De esa manera, NUNCA distribuya su clave privada en ningún formato.
fuente
Basado en una experiencia amarga, y después de consultar con un experto IDA-Pro, la mejor solución es mover una parte clave del código a un DLL / SharedObject, luego buscarlo desde un servidor y cargarlo en tiempo de ejecución.
Los datos confidenciales deben codificarse, ya que es muy fácil hacer algo como esto:
fuente