Buenas prácticas de desarrollo seguro: A7 – Secuencia de comandos en sitios cruzados (XSS)

La vulnerabilidad por XSS es la segunda más frecuente en el Top 10, la encontramos en muchas aplicaciones web. XSS es un vector de ataque que puede ser utilizado para robar información delicada, secuestrar sesiones de usuario, y comprometer el navegador, comprometiendo la integridad del sistema. Utiliza, en parte, la ingeniería social aprovechándose de la confianza que tiene un usuario en una página web. 

¿En qué consiste el Cross Site Scripting (XSS)?

Es un ataque de inyección de código que permite a un atacante ejecutar un script malicioso en una aplicación web dinámica.

Los XSS ocurren cuando una aplicación toma datos no confiables y los envía al navegador web sin una validación y codificación adecuada; o actualiza una página web existente con datos suministrados por el usuario utilizando una API que ejecuta JavaScript en el navegador.

Permiten ejecutar comandos en el navegador de la víctima y el atacante puede secuestrar una sesión, modificar los sitios web, o redireccionar al usuario hacia un sitio malicioso.

Hay tres formas de XSS para atacar a los navegadores de los usuarios:

·XSS Reflejado o no persistente: Una URL transporta un parámetro modificado que actúa al ser accedido por un visitante. Es decir que el código que insertamos no se queda almacenado en la web, sino que va insertado dentro de un enlace que llega de algún modo a la víctima para que pinche en él, una vez hecho eso el navegador dirigirá a una página donde el usuario tenga cuenta o deba rellenar algún formulario, allí ejecutará el código (malicioso) insertado y el atacante le robará la cookie de la sesión, o los datos insertados en el formulario. Lo complejo de este ataque, como nombramos más arriba, es que nada queda almacenado en el servidor web.

·XSS Almacenado o persistente:  La API almacena datos proporcionados por el usuario sin validar ni sanear, los que posteriormente son visualizados o utilizados por otro usuario o un administrador. Usualmente es considerado como de riesgo de nivel alto o crítico.

Imagen referencial.

En ambos casos, el atacante malicioso inyecta código sobre algún campo de entrada de datos que ofrezca la página web, bien sea este la típica cajita con el icono de la lupa para búsqueda de palabras clave, un recuadro de espacio de participación en un foro, o un formulario de recogida de datos.

·XSS Basados en DOM: : frameworks en JavaScript, aplicaciones de página única o APIs incluyen datos dinámicamente, controlables por un atacante. Idealmente, se debe evitar procesar datos controlables por el atacante en APIs no seguras.

Los ataques XSS incluyen el robo de la sesión, apropiación de la cuenta, evasión de autentificación de múltiples pasos, reemplazo de nodos DOM, inclusión de troyanos de autentificación, ataques contra el navegador, descarga de software malicioso, keyloggers, entre otros.

Hoy existen herramientas automatizadas que permiten detectar y explotar las tres formas de XSS, y también se encuentran disponibles kits de explotación gratuitos.

El impacto de XSS es moderado para el caso de XSS Reflejado y XSS en DOM, y severa para XSS Almacenado, que permite ejecutar secuencias de comandos en el navegador de la víctima, para robar credenciales, secuestrar sesiones, o la instalación de software malicioso en el equipo de la víctima.

Cómo prevenir los XSS

Dado que los ataques XSS ocurren debido a inyecciones de código, es necesario que se manejen adecuadamente las entradas de información que la aplicación utilizará.

Es importante que todos los parámetros de entrada sean correctamente validados y filtrados de acuerdo a distintos criterios. El tratamiento de estos datos puede ser:

  • Filtrar: En base a patrones o expresiones regulares, determinar qué tipo de datos acepta el sistema y cuales no.
  • Escapar: Aceptar todo tipo de datos, pero escapándolos correctamente.
  • Sanear: Aceptar todo tipo de datos, pero eliminando el contenido inapropiado.
  • Transformar: Aceptar todo tipo de datos, pero transformándolos a un tipo de datos aceptado.

Debemos entender la diferencia que existe entre estos distintos métodos, ya que se debe adaptar al funcionamiento de la aplicación. Por ejemplo, si tenemos un editor de texto enriquecido, mediante el cual se permite al usuario manipular código HTML, en este caso no deberíamos optar por la opción de escapar los caracteres, ya que al momento de mostrar la información el navegador no lo interpretará y lo mostrará como texto.

Para entender como funcionan cada uno de estos metodos, creamos la siguiente tabla:

En el input de ejemplo se puede ver un script javascript, el cual gatilla una alerta en el navegador. Dependiendo el tipo de método que apliquemos sobre los parámetros de entrada, podemos ver el output que deberíamos obtener.