En esta ocasión, el artículo sobre el TOP 10 del catálogo de vulnerabilidades de OWASP del año 2010 se basa en la vulnerabilidad conocida como XSS, cuyas siglas en inglés se traducen como Cross Site Scripting. Por si alguien se lo está preguntando, la X es realmente una cruz y de ahí lo de Cross, ya que tuvieron que buscarle unas siglas que no pudieran confundir con CSS, Cascade Style Sheet. La nomenclatura es la misma que en Xing, la red social de profesionales, por lo que si alguna vez hay que pronunciarlo: será mejor hacerlo como crossing.
Pero dejemos las siglas para otro post y centrémonos en el XSS. Esta vulnerabilidad ha estado presente en las tres clasificaciones de OWASP. En el 2004 se consideró la cuarta vulnerabilidad más encontrada, en 2007 se posicionó en la primera posición de esta clasificación y en esta nueva versión del 2010 continúa en la parte alta ocupando la segunda posición, únicamente superada por la Inyección, que ya vimos en el anterior post de la serie.
Las vulnerabilidades de XSS son explotadas cuando una aplicación obtiene datos de cualquier fuente y los envía al navegador del usuario sin realizar una validación previa de los datos. Este tipo de vulnerabilidades permiten a un atacante ejecutar código arbitrario en el navegador del usuario permitiendo el robo de sesiones, defacement de páginas web (¿se acuerdan de Mr. Bean en la página de la presidencia de turno del Gobierno?), o incluir código malicioso de páginas no confiables por el usuario en otras que sí lo son.
Existen tres situaciones en las que nos podemos encontrar ante una aplicación vulnerable a ataques XSS:
- Utilizando los parámetros que se envían a través de una URL,
- utilizando información almacenada en el back end de datos del servidor y
- utilizando el propio objeto DOM que representa la página web que se está visualizando.
Veamos el siguiente ejemplo como demostración del tipo de situaciones en las que podemos encontrar un ataque de XSS a través de una URL. Sea una aplicación que dispone de un frontal web en el que se muestra un formulario. Al seleccionar el usuario una determinada categoría, pulsa el botón de buscar y le aparece el conjunto de artículos que contiene dicha categoría. Al pulsar sobre “Seleccionar”, se envía una petición al servidor del tipo:
Una vez recibida en el servidor, obtiene el listado de artículos y devuelve la información, así como el identificador de la categoría que quedará almacenado en un input oculto para su posterior utilización de la forma:
<input type='hidden' name='category' id='category' value='<%=request.getParameter(“id”)'/>
Un atacante de nuestra plataforma podría modificar la petición esperada que provocase que no se retornará ningún artículo de la categoría pero le permitiese, por ejemplo, recuperar la cookie de sesión del usuario y realizar cualquier acción que considere oportuna:
Para que esta vulnerabilidad sea efectiva y el usuario pueda ser atacado es necesario engañarlo, por ejemplo a través de un correo en el que se solicita que pulse un determinado enlace que visualmente apunta a una página “segura” en la que se ofuscan los parámetros que pueden ocasionar la vulnerabilidad. Si no conocían esta vulnerabilidad, es posible que a partir de hoy le tengan tanto respeto como yo a los acortadores de URL tipo http://bit.ly/9Uc1S4 o http://tinyurl.com/382hyoz, pero esto ya lo trataremos en otro post.
Del mismo modo, es posible mostrar un ejemplo de vulnerabilidad de XSS basada en el árbol DOM que representa la página web que está visualizando el usuario. Sea una aplicación que permite la selección de lenguaje a través de un parámetro con el siguiente aspecto:
Seleccione su idioma: <select> <script> document.write(“<option value=1></option>”); document.write(“<option value=2>”+ document.location.href.substring(document.location.href.indexOf(“lang=”)+8 +”</option>”); document.write(“<option value=3>English</option>”); </script> </select>
Al seleccionar se envía una petición al servidor del tipo:
Un atacante de nuestra plataforma podría modificar la petición esperada que provocase que no se realizase un cambio en el lenguaje de la interfaz pero le permitiese, de nuevo, recuperar la cookie de sesión del usuario y realizar cualquier acción que considere oportuna:
Sin aprovechar ningún problema de validación en el servidor que recibe la petición ésta se transforma en un alert con la cookie del usuario en pantalla.
Por último, es posible aprovechar vulnerabilidades XSS permanentes procedentes del back end de datos del servidor de la aplicación, siendo esto posible si un mal diseño ha permitido a un usuario incorporar estos valores a través de la propia aplicación o mediante la explotación de alguna vulnerabilidad, por ejemplo las de inyección explicadas en el post anterior de la serie. De nuevo utilizamos el mismo ejemplo que desea obtener el listado de artículos de una categoría y las representa en una tabla con id, nombre y precio con una petición del tipo:
Supongamos que la tabla la compone directamente el back end del servidor en Java de la forma:
List<article> articles = proxyCategory.getArticles(id); StringBuffer sbItem = new StringBuffer(“<table>”); for (Article article : articles) { sbItem.append(“<tr><td>”). .append(article.getId()) .append(“</td><td>”). .append(article.getDescription()) .append(“</td><td>”) .append(article.getPrice()) .append(“</td></tr>”); } sbItem.append(“</table>”)
Si la información almacenada en el back end ha sido comprometida, será posible que en el campo descripción, suponiendo que éste sea el único campo de tipo alfanumérico, se puedan incorporar datos maliciosos que puedan ocasionar una pérdida de información en la interfaz del cliente, de la misma forma explicada en los anteriores ejemplos. Para que esta vulnerabilidad sea efectiva y el usuario pueda ser atacado ya no es necesario engañarlo sino que la propia infraestructura del servidor al que se conecta es la que ha sido comprometida.
Al igual que en la entrada anterior, hemos realizado la muestra de vulnerabilidades a través de peticiones GET, siendo extensible a las peticiones POST sin que los ejemplos se vean alterados. Del mismo modo, estas vulnerabilidades son independientes del lenguaje utilizado en el servidor.
Aunque la primera manera de protegerse pueda considerarse eliminar por completo el uso de javascript en la página con plugins del tipo NoScript, siempre existirán páginas en las que confiaremos y para las que habilitaremos el uso de esta tecnología. Es por tanto necesario, desde el punto de vista del programador, incorporar los controles necesarios en la programación del servidor para mitigar y eliminar este tipo de vulnerabilidades. El resto de aspectos son similares a los que comentamos la última vez: es fundamental sanear las entradas: si el valor esperado es un número, que sólo pueda ser tratado un número, si es una cadena de texto, se deben validar que los caracteres incluidos sólo puedan contener caracteres válidos. En caso de que la aplicación desarrollada deba permitir el uso de caracteres especiales, se deberá tratar con especial atención esta información y garantizar que la información que se está tratando es adecuada antes de aceptar los datos.
Y hasta aquí todo lo referente a ataques de XSS, de momento. Como saben, si quieren extenderse en la materia, más allá de los innumerables recursos de la red, pueden acudir a la web de OWASP, donde encontrarán mucha información de utilidad. Si desean que demos más detalles sobre alguna de las vulnerabilidades mostradas, o no les ha quedado clara la explicación, no tienen más que indicarlo en los comentarios y estaremos encantados de ampliar la información.
Que grande eres David. Un post muy bien explicado, el único pero a mencionar, es que usaras en algunos ejemplos Java y no C o ensamblador jeje. Fuera bromas, muchas gracias por emplear tú tiempo en escribir estos artículos tan buenos.
document.location ;)
Muchas gracias por el comentario Ximo
Estoy dispuesto a poner los ejemplos en casi cualquier lenguaje de programación que sea necesario. Si alguien considera que le sería más útil el post con ejemplos en php, asp o python, por poner un ejemplo, tan sólo será necesario que lo indiquen en los comentarios.