En el mundo del desarrollo para aplicaciones móvil, la seguridad de nuestras aplicaciones es una prioridad.. o al menos debería serlo, dependiendo de que estámos hablando.
Muchas veces, al implementar mecanismos como una revisión HMAC-SHA256 para proteger la comunicación o validar datos, olvidamos una parte muy crucial: dónde y como almacenar la clave secreta.
En este post explicaremos y daremos un buen ejemplo en el que hay que tener en cuenta y cuidado en como se manejan las claves secretas en una aplicación Android, especialmente cuando se utilizan para implementar algoritmos de verificación como HMAC-SHA256. Aunque esta medida parezca una solución robusta para garantizar la integridad de los datos, guardar la clave dentro de la aplicación es una práctica que conlleva riesgos significativos.
En este caso, pondremos a Adif como nuestro ejemplo. Adif ofrece una aplicación Android en el que te deja ver horarios y informaciones de las estaciones a tiempo real, esta te proporciona datos reales y puntuales de los trenes, con observaciones, etc. Ahora mismo tu te estarás preguntando, ¿de dónde se sacan estos datos?
Adif tiene una API secreta, bueno, “secreta”, la cual requiere parametros de autenticación para poder usarla. Es como una revisión para saber de que tienes permiso para usar la API y no tienes intenciones de abusarla. La API espera que enviemos unos encabezados que estamos mandando al servidor pero firmados con una clave HMAC-SHA256. ¿Por qué? Simple, esta medida se hace para que la API no la usen las personas. ¿Es posible usar esta API? Sí, aún que es un poco tedioso y complicado, es posible, haciendo ingeniería inversa.
La ingeniería inversa
Primero, tenemos que saber como la aplicación está mandando las peticiones. Para hacer esto, se puede usar una aplicación como Reqable (Necesita un teléfono rooteado) para poder mirar las peticiones que hace una aplicación.
La API espera algo como esto:
POST /portroyalmanager/secure/circulationpaths/departures/traffictype/ HTTP/2
host: circulacion.api.adif.es
user-key: f4ce9fbfa9d721e39b8984805901b5df
authorization: HMAC-SHA256 Credential=and20210615/20241029/AndroidElcanoApp/48875f934d7117ec/elcano_request,SignedHeaders=content-type;x-elcano-host;x-elcano-client;x-elcano-date;x-elcano-userid,Signature=e02df47713252d1d5b3b952d0b5c78c7a68c2043055c052d51d9d5e31820aa9b
x-elcano-client: AndroidElcanoApp
x-elcano-date: 20241029T180652Z
x-elcano-host: circulacion.api.adif.es
x-elcano-userid: 48875f934d7117ec
content-type: application/json;charset=utf-8
content-length: 126
accept-encoding: gzip
user-agent: okhttp/4.12.0
{"commercialService":"YES","commercialStopType":"YES","page":{"pageNumber":0},"stationCode":"64203","trafficType":"CERCANIAS"}
Seguramente no entiendas que es lo que está sucediendo aquí, vamos a explicarlo paso a paso.
Esto, en formato de que un humano pueda leerlo, se ve de la siguiente manera. Imagínate que eres un periodista que necesita información actualizada sobre los trenes que están saliendo de una estación específica para escribir un artículo o informar a tus lectores. Vamos a traducir esta solicitud técnica en una metáfora fácil de entender:
Piensa que estás llamando a la oficina de información de trenes de Adif (la empresa que gestiona las estaciones en España) para preguntar sobre los trenes de Cercanías que están saliendo desde la estación de Alfafar-Benetússer (código “64203”). Pero como esta oficina maneja información confidencial, necesitan estar seguros de que tú eres quien dices ser y que tienes permiso para acceder a esos datos. Así que antes de responder, te piden dos cosas:
-
- Una clave secreta: Les das una firma especial (el HMAC-SHA256) generada con una clave que compartiste con ellos previamente. Esto les asegura que tú eres realmente quien dices ser, porque solo tú y Adif conocen esa clave secreta.
-
- Identificación personal: Les das tu identificación como periodista (en este caso, las cabeceras
user-key
yx-elcano-userid
), y mencionas que representas a un medio específico (en este caso siendox-elcano-client: AndroidElcanoApp
)
- Identificación personal: Les das tu identificación como periodista (en este caso, las cabeceras
Una vez que Adif verifica tu identidad y la firma que les enviaste, procesan tu solicitud. En tu mensaje, estás pidiendo especificamente lo siguiente en un lenguaje claro:
- “Quiero información sobre los trenes de Cercanías (trafficType: CERCANIAS) que salen de la estación de Alfafar-Benetússer (código 64203)
- “Sólo me interesa los trenes que hacen paradas comerciales (commercialService: YES) y aquellos que se detienen para que los pasajeros puedan subir o bajar (commercialStopType: YES)”
- “Dame los datos de la primera página de resultados (pageNumber: 0)”
En respuesta, Adif revisa su base de datos y re devuelve los detalles de los trenes que cumplen con los criterios solicitados, como horarios, destinos, y más.
Ahora, ¿que pasa si tenemos las claves incorrectas?
Adif simplemente te dirá que no eres el periodista el cual dijiste que eras y simplemente no te dará acceso a esto.
Una vez teniendo esto en cuenta, vamos a mirar como podemos hacernos pasar por un usuario real de Adif y mandar nuestras propias peticiones
Decompilar la aplicación de Android.
Para entender cómo se gestiona la generación del HMAC dentro de una aplicación Android, primero necesitamos descompilarla. Esto nos permitirá analizar su código y buscar dónde se encuentra la clave secreta y cómo se utiliza. Una herramienta útil para este propósito es JADX, que convierte los archivos APK en un formato más legible.
Después de varias horas de investigación, la clave se la pide a una librería con la función “getSecretKey()”. Como en los datos que nos dio JADX no se ve por ninguna parte, tendremos que subir un escalón mas. Tendremos que hackear la aplicación de Android para poder mirar mas a fondo que está pasando, te preguntarás, ¿cómo?
Frida.
Frida es una herramienta de instrumentación dinámica muy potente que permite analizar y modificar aplicaciones en tiempo real, sin necesidad de tener acceso al código fuente. Frida se usa principalmente para realizar reverse engineering (ingeniería inversa) en aplicaciones móviles o programas de escritorio, permitiendo interceptar y modificar funciones, llamadas a métodos o datos en ejecución.
¿Cómo funciona Frida?
Frida permite inyectar código JavaScript en una aplicación en tiempo de ejecución. Con esto, puedes “interceptar” y modificar el comportamiento de la aplicación, inspeccionar variables, y observar cómo se manejan las operaciones críticas como la autenticación o la criptografía.
Después de varias horas jugando con varios parametros finalmente obtuvimos la clave de encriptado, ¿ahora qué?
Ahora, tendremos que replicar en nuestro lenguaje de programación preferido el mecanismo de Adif. Adif lo que espera es que se firmen los encabezados de X-Elcano
con esta clave secreta, después pasarlo a hex. El resultado final, es la clave de autenticación.
Conclusión
En este artículo hemos explorado cómo, a pesar de las buenas intenciones de implementar seguridad mediante el uso de HMAC-SHA256, almacenar claves secretas dentro de una aplicación no es una práctica segura. A través de un ejemplo práctico con la API de Adif, vimos cómo un atacante con las herramientas adecuadas puede decompilar la aplicación, analizar el flujo de datos y obtener acceso a las claves necesarias para hacer solicitudes autenticadas.
El proceso de ingeniería inversa con herramientas como JADX y Frida demuestra que si las claves se mantienen dentro de la app, pueden ser fácilmente extraídas, comprometiendo así la seguridad de la comunicación. Además, replicar este proceso en tu propio código podría ser tan fácil como extraer esa clave y firmar las solicitudes correctamente.
Por todo esto, es fundamental adoptar mejores prácticas de seguridad, como almacenar las claves secretas en un entorno más seguro, por ejemplo, en un servidor o en un almacén de claves criptográficas, y no en la propia aplicación. Al hacerlo, garantizamos que, incluso si la app es descompilada, los atacantes no tendrán acceso a información crítica.
Finalmente, como desarrolladores, debemos ser conscientes de que la seguridad es un proceso continuo, y solo a través de la implementación de buenas prácticas y auditorías regulares podremos proteger adecuadamente los datos y la integridad de nuestras aplicaciones.