Denegación de Servicio en apps Web

A continuación encontrarás traducido al castellano un artículo escrito por Ricardo Cruz y publicado originalmente en el Blog oficial de Xojo.

La semana pasada recibimos un informe sobre un bug crítico que afectaba a las apps web creadas con Xojo. La codificación de un URL con la inclusión del caracter de porcentaje era suficiente para colgar la app web en el servidor. Algo tan breve como ?x=% en la cadena de una petición era todo lo necesario. Hemos publicado una solución a dicho problema en 2026r1.2, y Xojo Cloud también se ha parseado al nivel de la plataforma para cubrir a los usuarios que no se pueda actualizar. A continuación indicamos lo que ha sucedido, lo que hemos hecho y lo que puedes hacer en función del modo en el que se desplieguen tus apps.

¿Estoy afectado? ¿Qué he de hacer?

Si sólo vas a leer una sección, que sea esta.

  • ¿En Xojo Cloud (Web 1 o Web2)? Estás cubierto. No has de hacer nada.
  • ¿Usas Lifeboat? Actualiza Lifeboat y vuelve a desplegar la app.
  • ¿Alojas la app tras Apache o Nginx? Añade la regla de filtrado que se muestra a continuación. Si tienes Web 2, también deberías de actualizar a 2026r1.2 si te es posible.
  • ¿Alojas la app y está expuesta directamente? En Web 2, actualiza a 2026r1.2 si es posible; de lo contrario, incluye un proxy inverso. En Web 1, incluye un proxy inverso (lo cual es lo recomendable en cualquier caso).

Todos los detalles a continuación.

Línea temporal

  • Jueves, 23 de Abril. Una incidencia pública y un mensaje privado aterrizaron el mismo día, en ambos casos apuntando al mismo problema.
  • Jueves a Lunes. Hallamos la causa raíz, escribimos la solución y la probamos.
  • Martes 28 de Abril. Publicación de Xojo 2026r1.2 con el parche.
  • Miércoles 29 de Abril. Xojo Cloud parcheado a nivel de plataforma.

Menos de una semana desde la recepción de la incidencia hasta la publicación con el parche, con la mitigación a nivel de plataforma realizada al día siguiente.

Lo que ha ocurrido

Una petición con la codificación de un URL malformado en el parámetro podía colgar una app Xojo Web en ejecución. La forma más simple de reproducir el fallo es algo como ?x=%. Esto es el caracter de un porcentaje no seguido por dos dígitos en hexadecimal, lo cual resulta en una codificación no válida del porcentaje dado que no se puede decodificar.

El bug reside en DecodeURLComponent. Cuando el método ejecutaba la entrada no válida lanzaba una excepción, en vez de gestionar la entrada de forma más grácil. Dado a que el framework llama a este método cuando se parsean las peticiones entrantes, cualquier podía colgar una app web con un URL malformado. No se requería de autenticación, cabeceras especiales o carga adicional; simplemente una cadena con una petición malformada.

Algunas consideraciones:

  • Probablemente el bug haya estado ahí desde la misma introducción de DecodeURLComponent. Cada versión que incluía dicho método podría verse afectada.
  • Están afectadas tanto Web 1 como Web 2. El framework Web ha estado llamando a dicho método en las peticiones entrantes en ambas generaciones.
  • No sólo se trata de un problema Web. DecodeURLComponent es un método de propósito general y el mismo cuelgue puede ocurrir en Desktop u otros tipos de proyecto en el supuesto de que se utilizase dicho método sobre una entrada controlada por un atacante. Web es el destino obvio de dicho ataque dado que las peticiones llegan a través de la red; pero el problema subyacente no es específico a la web.

La solución

En 2026r1.2 el método DecodeURLComponent ya no produce cuelgues sobre una entrada no válida. En vez de ello devuelve una cadena vacía cuando la entrada contiene una secuencia con el caracter de porcentaje mal codificado.

Hemos pensado sobre varios enfoques sobre el problema, y hemos tomado esta decisión a propósito al ser consistente con otras comprobaciones de sanidad realizadas sobre dicho método. La devolución de una cadena vacía permite la ejecución del código existente en vez de dejar que se eleve una excepción en la gestión de la petición, lo cual es lo que probablemente desees sobre un método que se llama de forma constante sobre una entrada no confiable. Si tu código ya se encarga de trabajar con DecodeURLComponent para realizar dicha validación, entonces el nuevo comportamiento te permite obtener una señal más clara sobre la cual actuar (un resultado vacío) en vez de tener que lidiar con la excepción generada.

Xojo 2026r1.2 es la única versión con esta corrección. Web 1 no obtendrá el parche. A continuación cubrimos lo que significa esto en la práctica.

Lo que Xojo ya ha hecho por ti

Xojo Cloud se ha parcheado a nivel de plataforma. Desde el Miércoles 29 de Abril, Xojo Cloud descarta las peticiones que incluyan el caracter de porcentaje malformado, antes incluso de que llegue a tu app, devolviendo un 400 Bad Request desde el front-end del servidor web. Esta protección no se aplica sobre una versión de Xojo específica que se haya utilizado para crear la app, y cubre tanto a Web 1 como a Web 2 del mismo modo.

Si tu app se ejecuta sobre Xojo Cloud, entonces no tendrás que volver a desplegar o cambiar cualquier cosa. Hemos desplegado esto específicamente de modo que los usuario que no puedan actualizarse ahora mismo estén cubiertos, incluyendo por tanto los usuarios de Web 1 que no puedan actualizarse a la versión de Xojo en la que se incluye el parche.

Lo que deberías de hacer

El movimiento correcto depende de la versión Web que estés utilizando y de cómo se estén ejecutando tus apps.

Si usas Web 2

Actualiza a 2026r1.2 y vuelve a desplegar si te es posible. Es la forma más limpia de corrección y cubre la incidencia en la fuente.

Sabemos que “sólo has de actualizar” no siempre es lo más realista. Puede que estés utilizando una versión anterior porque tu licencia haya expirado, debido al uso de un plug-in de terceros o porque una nueva versión de Xojo ha introducido una regresión que no te permite desplegar, o cualquier otro tipo de razón. Si es tu caso, las mitigaciones basadas en el hosting que encontrarás a continuación protegerán tu app entre tanto; y funcionarán sin importar la versión de Xojo con la que hayas compilado la app.

Si estás en Web 1

No hay versión de Xojo que corrija DecodeURLComponent para Web 1, de modo que la solución ha de aplicarse fuera de la app. La buena noticia es que si sigues las recomendaciones de alojamiento de Xojo, entonces estarás cubierto contra este problema concreto:

  • Si usas Xojo Cloud, ya estás protegido.
  • Usar Lifeboat. Tim Parnell ha publicado una actualización de Lifeboat que lidia con los URL malformados antes de lleguen a tu app. Actualiza Lifeboat y vuelve a desplegar.
  • Si utilizas Apache o Nginx, utiliza las reglas de la siguiente sección.

Por otra parte, y en un horizonte más lejano: Web 1 no recibe correcciones del framework en general; de modo que, si aun estás utilizando Web 1, entonces este sería un momento razonable para comenzar a pensar en la migración a Web 2. Se trataría de una conversación mucho más larga que este artículo, pero merece la pena indicarlo.

Mitigaciones a nivel de Hosting

Esta reglas descartan los URL con la codificación del caracter de porcentaje malformada en el servidor Web, antes de que la petición llegue a tu app Xojo. Funcionan tanto con Web 1 como con Web 2, y no dependen de la versión de Xojo que hayas utilizado.

Apache:

# Reject malformed percent-encoding in the URI.
RewriteCond %{THE_REQUEST} %(?![0-9A-Fa-f]{2})
RewriteRule .* - [R=400,L]

Nginx:

# Reject malformed percent-encoding in the URI.
if ($request_uri ~ "%(?![0-9A-Fa-f]{2})") {
return 400;
}

Recarga tu servidor web una vez que hayas actualizado el archivo de configuración (apachectl graceful o nginx -s reload), y comprueba que una petición como https://yourapp.example.com/?x=% devuelve un 400 Bad Request.

Los anteriores fragmentos no suponen la única forma de gestionar esto. El objetivo es simplemente bloquear los URL malformados antes de que lleguen a tu app. Si estás ejecutando mod_security, por ejemplo, entonces una regla que rechace los URL malformados en los que se contenga el caracter de porcentaje mal codificado te ofrecerá el mismo resultado. Lo mismo aplica a cualquier WAF, filtro de perímetro, CDN o balanceador de carga que se encuentre en la primera línea de tu pila: atrapa la petición malformada, devuelve un 400, y listo.

Si tu app Xojo está expuesta directamente a Internet

Si tu app web está expuesta a Internet sin utilizar un proxy inverso, entonces tus opciones son más limitadas. En Web 2, actualiza a 2026r1.2 si puedes. En Web1 o Web 2, y si la actualización no es una opción, entonces tendrás que poner Apache, Nginx o Lifeboat frente a tu app, o bien utilizar Xojo Cloud o una solución de alojamiento gestionada.

También es un buen momento para revisitar la configuración de una forma más amplia. Xojo recomienda servir las apps web siempre tras un servidor web, tanto por rendimiento como por tratarse de una medida con mayor capacidad de defensa frente a un bug de estas características. Un proxy inverso podría haber neutralizado esta incidencia en concreto antes de que alcanzase al framework, y también hará lo mismo con la siguiente incidencia del mismo tipo que se pueda producir.

Si utilizas DecodeURLComponent en un proyecto no Web

El cuelgue no es exclusivo a los proyectos Web. Si llamas a DecodeURLComponent sobre una entrada que no controles (algo que provenga de la entrada del usuario, un archivo o una respuesta de red, o bien copiado desde el portapapeles), entonces el mismo bug puede alcanzar a Desktop, Consola o bien otro tipo de proyecto.

Actualiza a 2026r1.2 si te es posible. Es la solución adecuada.

Si no puedes actualizar, tendrás que sanitizar la entrada tu mismo antes de llamar a DecodeURLComponent (por otra parte, lo siempre recomendable en cualquier caso). La comprobación es sencilla en principio: cada % en la cadena ha de contar con exactamente dos caracteres hexadecimales a continuación (0-9, A-F, a-f). Si cualquier % no cumple con dicha condición, entonces trata la entrada como no válida y no la pases a DecodeURLComponent.

Agradecimientos

Gracias al usuario que informó sobre este problema tanto en los canales público como en privado. Este es exactamente el tipo de información que nos permite desplegar una solución en menos de una semana. Gracias también a Tim Parnell por su rápida actualización de Lifeboat, proporcionando de dicho modo una mitigación casi inmediata a los usuarios que alojan ellos mismos sus apps.

Por favor, reporta de forma privada si encuentras un fallo de seguridad en Xojo. Puedes enviar un email a support@xojo.com o bien crear una incidencia confidencial en Issue Tracker. Ambos llegan a nosotros y nos permiten solucionar el problema antes de que los detalles se hagan públicos, protegiendo así al resto de los usuarios.

Referencias

Notas de revisión correspondientes a Xojo 2026r1.2

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *