¿Por qué deberías ofuscar tu aplicación?

La transformación digital, presente en todos los ámbitos de nuestra vida, ha convertido los dispositivos digitales, especialmente los teléfonos móviles, en nuestro principal medio para gestionar prácticamente todas nuestras actividades diarias. Esto nos ofrece grandes facilidades, pero también implica volcar sobre la red nuestra información más privada y vulnerable. Por esta razón es importante aplicar mecanismos que garanticen la seguridad de las aplicaciones móviles.

Uno de los mecanismos más importantes de cara a proteger la información privada de los posibles atacantes es la ofuscación.

Índice de contenidos:

¿Qué es la ofuscación?

Se llama ofuscación al conjunto de técnicas para transformar un código comprensible y coherente en uno en el que los elementos no tengan coherencia semántica ni lógica. De esta forma se pretende que cualquier persona o sistema que pretenda descubrir su funcionamiento interno tenga dificultades para hacerlo.

Se trata de actuar de forma contraria a lo que un desarrollador pudiera considerar como buenas prácticas a la hora de diseñar y escribir su aplicación. Nombrar los elementos de código con letras inconexas, introducir bloques de código innecesarios y eliminar todo tipo de comentarios explicativos son algunas de las cosas que se pueden hacer.

La ofuscación se puede aplicar tanto en el código original, en el intermedio o incluso en el compilado.

Más adelante se describen algunas de las herramientas y opciones disponibles que nos facilitan, como desarrolladores, aplicar métodos de ofuscación de forma preconfigurada y segura. Estas herramientas suelen tener un archivo de instrucciones predefinidas para seleccionar técnicas a aplicar y partes de código o elementos específicos.

Las herramientas de ofuscación a menudo siguen un esquema en 3 etapas:

  • Shrinking: Eliminar tanto los elementos de código (clases, métodos, atributos) como los recursos del proyecto que no tienen ninguna utilidad aparente, simplificando el código.
  • Optimización: Inspeccionar y reescribir todo el código, tanto el original como el bytecode intermedio generado, para simplificar flujos innecesariamente complejos que pueden ralentizar su ejecución.
  • Ofuscación: Una vez limpiado, y optimizado el código, aplicar las técnicas de ofuscación escogidas para ocultar y enrevesar el código dificultando así su comprensión. Cifrar los elementos señalados.

Algunos ejemplos del antes y el después de la ofuscación:

Ofuscación de nombres de clases

Ofuscación de métodos, variables, textos y flujo

Mapa de ofuscación para comunicaciones

Riesgos de la ofuscación

Ofuscar un segmento de código implica algunos riesgos que se deben prevenir, ya que se trata de modificar el código para volverlo más complejo. 

Es recomendable evitar la ofuscación sobre los puntos de entrada del código que sirven de conexión con otros módulos. Liberar estos puntos de la ofuscación puede hacer el código más vulnerable, pero es necesario para que su compatibilidad se mantenga.

Además se debe seleccionar cuidadosamente los módulos sobre los que se aplica la ofuscación. Aplicarla sobre librerías externas de terceros de las que se desconoce la estructura podría provocar alteraciones que interrumpan su lógica interna, su funcionamiento en conjunto con otras librerías o la propia integración con el código principal.

Es altamente recomendable aplicar las técnicas de ofuscación mediante herramientas que lo hagan de forma automática y que permitan invertir los cambios de forma segura. De lo contrario no solo llevará mucho tiempo y esfuerzo, sino que dará como resultado un código muy complicado de mantener y evolucionar. Además de dificultar, como es obvio, el rastreo de posibles errores de funcionamiento.

Por otro lado es también importante guardar cuidadosamente las referencias de mapeo generadas de un código ofuscado para poder identificar con facilidad los elementos alterados en caso de necesidad.

Posibles ataques de seguridad

Son muchos los tipos de ataque que un dispositivo móvil puede recibir. La ofuscación no protege al usuario de todos los ataques… pero los dificulta de manera notable.

A continuación se describen algunos de estos ataques a los que es posible hacer frente ofuscando el código.

  • Tampering: Manipulación del código a ejecutar con el objetivo de modificar los flujos del programa y alterar su comportamiento. Un ejemplo de este ataque es la modificación y envío de los parámetros de una petición web obteniendo así una respuesta del servidor inicialmente inaccesible. Si el código está ofuscado, el atacante tendrá dificultades para identificar los flujos y parámetros del programa que debería manipular para lograr sus objetivos.
  • Decompilación / Ingeniería inversa: Análisis exhaustivo del código de programa para tratar de comprender su funcionamiento. Si el código está ofuscado, será complicado identificar los elementos que lo componen. La ingeniería inversa sirve para obtener información que luego se puede utilizar de muchas formas, entre ellas, el tampering, descrito anteriormente.
  • Ataques de entorno (debugging, emulation, rooting): Son aquellos ataques que ocurren por haber modificado el entorno en el que se ejecuta el código. Su objetivo es construir un entorno aparentemente seguro en el que lanzar el programa mientras se captura las trazas que va generando y obtener información privada. Con la ofuscación, no se puede evitar que ocurran este tipo de ataques, pero sí se puede ocultar la información para que el atacante, incluso llegando a capturarla, sea incapaz de interpretarla.

Herramientas para ofuscar tu código

Es recomendable aplicar la ofuscación mediante herramientas que lo hagan de forma automática para poder configurar, rastrear y revertir la ofuscación aplicada. Algunas de estas herramientas son gratuitas o de código libre. Otras, que incluyen técnicas más avanzadas, son herramientas de pago. A continuación, se mencionan algunas para los diferentes sistemas operativos móviles.

Android

  • R8: Es la opción gratuita ofrecida por Google que se puede aplicar fácilmente desde la propia configuración del proyecto en Android Studio. Ofrece las técnicas básicas de ofuscación, optimización y shrinking del código de la aplicación.
  • Proguard: Es la opción gratuita open source de la compañía GuardSquare para Kotlin, Java y bytecode. Dispone de una amplia documentación además de una comunidad de desarrollo que facilita su integración. Ofrece:
    • Ofuscación de clases, métodos y campos
    • Shrinking y optimización del código
  • Dexguard: Es la opción de pago de la compañía GuardSquare con prestaciones añadidas sobre la opción gratuita descritas en la comparativa. Dispone de un servicio de soporte exclusivo de gran ayuda. Ofrece:
    • Las funciones básicas de la versión gratuita
    • Ofuscación de recursos y librerías nativas
    • Cifrado de todo tipo de elementos, recursos y dependencias
    • Virtualización de código
    • Técnicas avanzadas de ocultación de código (reflection, arithmetic obfuscation, flow obfuscation, etc.)
    • Runtime Application Self-Protection (RASP): detección de comportamientos sospechosos en tiempo de ejecución.
  • Bitguard: Es la opción de pago para código en C++ de la compañía GuardSquare.

iOS

  • iXGuard: es la opción de pago para aplicaciones iOS de la compañía GuardSquare y sus prestaciones son equivalentes a su opción de pago para Java. Ofrece las técnicas básicas y avanzadas de ofuscación, así como protección en tiempo de ejecución RASP.
ixguard guardsquare

Mecanismos de protección aplicables

A continuación, se describen algunas de las técnicas que se utilizan en la ofuscación de código para transformar el código original en uno de difícil comprensión. La mayoría de estas técnicas se pueden aplicar de forma automática mediante las herramientas de ofuscación correspondientes.

  • Design obfuscation (ofuscación estructural): unir varias clases en una sola, dividir el contenido de una clase en varias diferentes o utilizar interfaces para enmascarar las clases para dificultar la identificación de los objetos.
  • Core design (diseño robusto): utilizar buenas prácticas de diseño para formar un código limpio, compacto y robusto incluso aunque esté sin ofuscar. Esto facilitará que, una vez ofuscado, el código sea aún más seguro.
  • Secure communications (comunicaciones seguras): aplicar protocolos de cifrado y ofuscación de información en las comunicaciones para que solo los interlocutores puedan invertir el proceso y ningún atacante que intercepte la comunicación sea capaz de obtener información sensible.
  • Name obfuscation (ofuscación de nombres): renombrar todo tipo de archivos, clases, campos, métodos y recursos utilizando nombres que no tengan un significado. Esto dificultará la identificación de los elementos que forman el programa y su utilidad, además de reducir el tamaño del código.
  • String encryption (ofuscación de textos): cifrar las cadenas de caracteres almacenadas en el programa que tras la compilación siguen siendo visibles. Estas cadenas a menudo contienen instrucciones, mensajes de error o incluso claves que pueden ser de interés para un atacante, por eso es recomendable ocultarlas.
  • Reflection (reflexión): sustituir y mapear los métodos, clases o elementos que no pueden cambiarse de nombre para ocultar sus nombres originales. De esta forma se mantienen intactos pero sus llamadas se hacen mediante invocaciones indirectas que confunden al atacante.
  • Flow obfuscation (ofuscación de flujos): analizar y reconstruir los flujos del programa de forma que no sigan un curso natural y puedan confundir al atacante en el análisis del funcionamiento del mismo.
  • Code virtualization (virtualización de código): para los elementos y clases que no se pueden renombrar por requisitos del programa, se inserta una máquina virtual que reimplementa los métodos partiendo de un elemento aleatorio.
  • Log and trace removal (eliminación de logs y trazas): eliminar todas las llamadas que invoquen escritura de logs y evitar todo tipo de comentarios o elementos descriptivos que puedan dar una descripción del funcionamiento interno.
  • Tamper detection (detección de tamper): detectar si el código ha sido alterado por un atacante para insertar logs que muestren información sensible u otros elementos de código.
  • Environment checks (comprobaciones de entorno): comprobar que el código se ejecuta en un entorno seguro, libre de condicionantes que puedan permitir al atacante ejecutar la aplicación con acceso a información que no debería poder obtener.
  • Resource, asset and string encryption (cifrado de recursos, archivos y textos): cifrar los archivos y assets que puedan tener elementos gráficos, vídeos, textos, metadatos u otro tipo de recursos con información sensible. Estos elementos serán descifrados en tiempo de ejecución.
  • Native library encryption (cifrado de librerías nativas): cifrado de librerías nativas y sus enlaces con la aplicación (JNI). Incluso aunque el atacante tenga acceso a las librerías utilizadas, de este modo no podrá identificar las llamadas que se están haciendo ni tratar de reproducirlas.
  • Intermediate code obfuscation (ofuscación de código intermedio): ofuscación del código bytecode generado a partir del código original para evitar que la decompilación sea comprensible. De este modo el código será enmascarado por duplicado haciendo aún más difícil su obtención en el estado original.

Conclusiones

La ofuscación es un conjunto de técnicas utilizadas para dificultar la comprensión de un código y los elementos que lo acompañan, de forma que un atacante sea incapaz de identificar sus elementos y descubrir su funcionamiento interno.

Lo más adecuado, rápido y seguro es aplicar ofuscación mediante herramientas automáticas que permitan configurar y revertir los cambios aplicados, de lo contrario podría perderse información de forma permanente. Además es importante vigilar que la ofuscación no afecte a la interoperabilidad entre el código y sus dependencias.

Dadas las posibilidades tanto gratuitas como de pago que se ofrecen actualmente, mantener tu aplicación correctamente ofuscada es accesible y recomendable. Esto te ayudará a prevenir todos aquellos ataques derivados de exponer tu código en claro.

¿Necesitas ayuda para ofuscar tus aplicaciones? Desde NTS Seidor te ayudamos con el rendimiento, la seguridad y la robustez de tus aplicaciones de movilidad en Android, IOS, etc.