Instituto Nacional de ciberseguridad. Sección Incibe
Instituto Nacional de Ciberseguridad. Sección INCIBE-CERT

Ofuscación y desofuscación en ciberseguridad: protegiendo y revelando el código fuente

Fecha de publicación 16/04/2026
Autor
INCIBE (INCIBE)
Ofuscación y desofuscación en ciberseguridad: protegiendo y revelando el código fuente

La ofuscación de JavaScript es una técnica comúnmente utilizada para proteger el código fuente de una aplicación web, dificultando su comprensión por parte de atacantes que pudieran realizar ingeniería inversa del código para descubrir vulnerabilidades, copiar funcionalidades o acceder a datos sensibles. Sin embargo, esta técnica no es infalible y puede ser desofuscada, exponiendo el código a diversos riesgos de seguridad. En un entorno donde el JavaScript se utiliza ampliamente para mejorar la interactividad y funcionalidad de las aplicaciones web, es esencial comprender tanto las ventajas, como las limitaciones de la ofuscación para proteger adecuadamente el código.

Uno de los principales problemas que vemos en el desarrollo de aplicaciones web es la tendencia a resolver demasiada lógica en el cliente. En muchos proyectos, la validación de datos, el procesamiento de información o incluso los cálculos computacionales complejos se delegan al navegador mediante JavaScript. Si bien JavaScript es potente y flexible, esta sobrecarga en el lado del cliente es un claro síntoma de una mala arquitectura.

El cliente, es decir, el navegador del usuario no debería ser responsable de manejar tanta lógica crítica de una aplicación. Exponer demasiada lógica en el cliente mediante JavaScript puede tener consecuencias graves:

  • Exposición del código: todo el código que se ejecuta en el cliente puede ser visible. Esto significa que cualquier lógica o validación crítica que se realice en el lado del cliente puede ser descompuesta y entendida por atacantes, exponiendo la estructura de la aplicación.
  • Dependencia de validaciones locales: un error común es confiar en que las validaciones hechas en el cliente son suficientes. Por ejemplo, las aplicaciones suelen usar JavaScript para validar formularios o asegurar que los usuarios ingresen datos correctos. Sin embargo, si estas validaciones no se replican o refuerzan en el servidor, un atacante podría modificar fácilmente los datos antes de que lleguen al backend, eludiendo las restricciones que fueron configuradas en el lado del cliente.
  • Posibilidad de manipulación: los usuarios con conocimientos avanzados pueden modificar el código JavaScript en tiempo real. Si bien la lógica crítica de la aplicación, como autorizaciones o cálculos importantes, reside en el cliente, esto abre una puerta para que los atacantes manipulen esos datos, alteren resultados o accedan a funciones que no deberían estar disponibles.

La ofuscación de código consiste en transformar el código fuente legible en una versión más difícil de entender para los humanos, sin alterar su funcionalidad, puede considerarse una medida de seguridad para paliar estos riesgos.

Patrones clásicos de ofuscación

Los patrones clásicos de ofuscación en JavaScript son técnicas comunes utilizadas para hacer que el código sea más difícil de leer y comprender, pero sin alterar su funcionamiento. Estas técnicas están diseñadas para ocultar la lógica real y dificultar el análisis, aunque muchas de ellas pueden ser revertidas por herramientas especializadas. A continuación, se explican algunos de los patrones más utilizados:

  • Renombrado de variables y funciones: uno de los patrones más comunes consiste en renombrar variables y funciones con nombres crípticos, cortos y sin significado. En lugar de nombres descriptivos como calculateSum, el código ofuscado usa nombres aleatorios como_0x1234a.
  • Concatenación de cadenas: las cadenas de texto que aparecen en el código suelen dividirse y concatenarse de forma innecesaria para dificultar su lectura. Esto se hace para que una cadena que antes era visible directamente se vuelva confusa y más difícil de detectar.
  • Codificación de cadenas: las cadenas de texto pueden codificarse en Base64, hexadecimal o Unicode, y luego decodificarse durante la ejecución. Esto oculta cadenas importantes como direcciones URL, rutas de archivos, claves API o mensajes del sistema.
  • Descomposición de expresiones: las expresiones simples se dividen en fragmentos más pequeños y se distribuyen en varias líneas o funciones para hacer el código más confuso.
  • Inserción de código muerto (Dead code): se agrega código innecesario que no afecta el resultado final del programa. Este código puede ser funciones o declaraciones adicionales que nunca se ejecutan, pero que incrementan la cantidad de código y confunden a quien lo analiza.
  • Funciones de ejecución dinámica: Se utiliza la función eval(), o construcciones similares, para ejecutar código que está almacenado en cadenas de texto. Esto hace que sea más difícil analizar el código porque no es visible directamente en el archivo fuente.
  • Cifrado de números y operaciones matemáticas: los números o valores numéricos se cifran o transforman en operaciones más complejas. En lugar de ver directamente un número, el código presenta operaciones largas y aparentemente innecesarias para llegar a ese valor.
  • Uso de objetos y arrays para almacenamiento de funciones: en lugar de llamar a las funciones directamente por su nombre, las referencias a funciones se almacenan en arrays o en objetos. Esto dificulta entender qué función se está ejecutando.
  • Transformaciones de flujo de control: los flujos de control sencillos como if o switch se reescriben en versiones más complicadas que usan combinaciones de operadores o múltiples funciones anidadas.

Ofuscación: factores de riesgo e impacto

A pesar de que la ofuscación puede dificultar la lectura directa del código JavaScript, no es una medida infalible. La ofuscación no impide que un atacante determinado entienda el flujo lógico del código, o que identifique puntos vulnerables que puedan ser explotados. Es una medida que puede complicar la tarea de los atacantes, pero no la detiene.

  • Ingeniería inversa: aunque la ofuscación puede dificultar la lectura directa del código, los atacantes pueden utilizar técnicas para deducir su lógica. Los atacantes pueden ejecutar el código, observar su comportamiento y, a partir de ahí, entender la funcionalidad clave, incluso si el código es ilegible. Un código JavaScript ofuscado que contiene lógica de autenticación en el cliente puede ser revertido, observando cómo interactúa con el servidor. Aunque la función tenga un nombre ofuscado como function _0x1a2b(c,d), un atacante puede usar las herramientas de desarrollo del navegador para ver las solicitudes enviadas y deducir que la función realiza una autenticación, descubriendo un posible punto débil. Chrome DevTools, Wireshark o cualquier proxy permiten observar el comportamiento del código, facilitando la deducción de su lógica a través de la ejecución.
  • Desofuscación: hay herramientas diseñadas específicamente para desofuscar el código JavaScript, permitiendo que los atacantes lo devuelvan a un estado más legible. Estas herramientas identifican los patrones comunes de ofuscación y los revertirán automáticamente. Una aplicación que utiliza ofuscación simple de JavaScript puede ser revertida con herramientas como JSNice o de4js.
Ejemplo Uso Desofuscacion Herramienta UnPacker Revertiendo Patron Eval


Ejemplo de uso de desofuscación con la herramienta UnPacker, revertiendo el patrón Eval – fuente propia

Deshacer o bypasear la ofuscación tiene un impacto directo en la comprensión de la lógica, la facilidad de modificación, y el robo de código. Los atacantes pueden entender rápidamente cómo funciona la aplicación, lo que les permite comprender la lógica empresarial crítica, como validaciones, autorizaciones o cálculos sensibles, expuestos en el lado del cliente. 

También facilita la modificación del comportamiento del código en tiempo real, permitiendo a los atacantes manipular las funciones de la aplicación en su beneficio, como eludir restricciones de acceso o cambiar parámetros sensibles. Además, una vez desofuscado, el código puede ser robado fácilmente, exponiendo algoritmos propietarios o lógica interna que puede ser reutilizada o explotada por competidores o actores maliciosos. Esto no solo compromete la seguridad de la aplicación, sino que también expone la propiedad intelectual de la empresa, destacando que la ofuscación, aunque útil, no es una barrera de seguridad robusta.

Evaluando la seguridad de la ofuscación

A menudo, los patrones de ofuscación son predecibles, lo que permite a los atacantes encontrar puntos débiles en el proceso de transformación. Un analista de seguridad experimentado podría evaluar la seguridad de la ofuscación de código usando varias técnicas.

  • El análisis estático del flujo de control es clave para contrarrestar varias técnicas de ofuscación. Este enfoque ayuda a deducir los nombres originales en el renombrado de variables y funciones. Asimismo, ayuda a recomponer expresiones dispersas cuando se aplica la descomposición de expresiones, lo que simplifica la lógica del programa. El análisis de flujo también identifica código muerto, revelando secciones innecesarias que no afectan el funcionamiento y que pueden eliminarse para obtener un código más claro.
  • La interceptación en tiempo de ejecución resulta efectiva frente a algunas técnicas, como la concatenación y codificación de cadenas o la ejecución dinámica. Capturar las cadenas ya decodificadas y reconstruidas durante la ejecución revela la información originalmente oculta, como claves o URL. Del mismo modo, interceptar el código dinámico generado con herramientas, como DevTools, permite visualizar el código que realmente se ejecuta, superando la barrera impuesta por funciones como eval().
  • El análisis de referencias a funciones es útil para deshacer el uso de objetos y arrays para almacenar funciones, ya que rastrea qué función es invocada en cada contexto, aclarando el flujo de ejecución. Además, este análisis simplifica las transformaciones de flujo de control complejas, devolviendo estructuras como ifswitch a su forma original y más comprensible.
  • Por último, el rastreo de operaciones matemáticas cifradas resuelve el cifrado de números y operaciones complejas, devolviendo las expresiones a sus valores originales y reduciendo la complejidad impuesta por la ofuscación.

Hay herramientas como JSNice, de4js, y UglifyJS que automatizan estos procesos total o parcialmente.

Medidas de protección y mejores prácticas

A pesar de los riesgos asociados con la desofuscación, existen varias medidas que pueden implementarse para fortalecer la protección del código JavaScript ofuscado. La primera recomendación es combinar múltiples técnicas de ofuscación. Aplicar diferentes métodos anidados, como el renombrado de variables, el cifrado de literales y la fragmentación de funciones, ayuda a dificultar considerablemente el proceso de desofuscación. Cuanto más variada sea la ofuscación, mayor será la complejidad para el atacante.

No obstante, aunque una ofuscación mejorada proteja el código que se ejecuta en el cliente, las funciones críticas, como la validación de datos y las operaciones sensibles, deben manejarse siempre en el backend o servidor, que debe ser el núcleo de la aplicación donde se debe procesar la lógica crítica, ejecutar cálculos importantes y validar de manera estricta cualquier información que provenga del cliente. Aunque JavaScript en el cliente puede manejar la interacción del usuario de manera eficiente, cualquier decisión clave, especialmente aquellas relacionadas con la seguridad, debe resolverse en el servidor. Esto no solo protege el código contra manipulaciones o análisis, sino que también permite centralizar la gestión de las reglas de negocio, lo que facilita su mantenimiento y actualización.

Conclusiones

Es fundamental adoptar una estrategia de defensa en profundidad. La ofuscación debe ser una de muchas capas de seguridad implementadas en la aplicación, junto con medidas como la protección contra ataques XSS, la verificación de la autenticidad de los usuarios y la implementación de políticas de seguridad estrictas en el servidor. Las auditorías regulares de seguridad y las pruebas de penetración también son esenciales para evaluar la efectividad de las medidas de protección y mejorar continuamente la seguridad de la aplicación.