Inicio > Hacking, Programacion, Services - Software, Web Applications > Vulnerabilidades comunes en HTML5 – Conociendo el funcionamiento de los WebSockets – Parte 3

Vulnerabilidades comunes en HTML5 – Conociendo el funcionamiento de los WebSockets – Parte 3

Históricamente las aplicaciones web se han basado en un modelo cliente-servidor, donde el cliente siempre es el primero en iniciar la comunicación con el servidor. Con la llegada de AJAX, las peticiones podían hacerse de forma asíncrona y el cliente no necesariamente tenia que esperar la respuesta del servidor para poder continuar trabajando con la aplicación web, sin embargo la comunicación tenia que ser iniciada por el cliente y si por algún motivo, el servidor tenia nueva información que debía transferirse al cliente, era el cliente el que tenia que realizar las peticiones contra el servidor para recuperar la nueva información. Evidentemente, el hecho de que el servidor pueda comunicarse con el cliente para informar sobre cualquier “novedad”, es una característica que siempre ha resultado muy útil y pensando en ello, se han diseñado varias alternativas que funcionan sobre el protocolo HTTP, como por ejemplo Comet, Push o con el uso de conexiones HTTP persistentes. Con estas alternativas, el servidor puede enviar datos al cliente sin que el cliente tenga que iniciar una interacción, son técnicas que se utilizan actualmente en muchos servicios en Internet y en su día, GMail también lo hacia, sin embargo, mantener una conexión HTTP durante un largo periodo de tiempo es costoso y no es una muy buena idea en aplicaciones que deben tener una baja latencia. Es aquí donde HTML5 viene “al rescate” con los websockets.

Los websockets son una alternativa muy óptima al problema descrito en líneas anteriores, ya que permite crear conexiones TCP utilizando sockets entre el cliente (navegador) y el servidor. Como con cualquier socket TCP, ambas partes pueden transferir datos en cualquier momento y de esta forma el servidor podrá enviar información al cliente cuando sea necesario.

Uso de websockets en HTML5

Para abrir una conexión entre cliente y servidor utilizando websockets, ahora se utilizan los esquemas “ws://” en lugar de “http://” y “wss://” en lugar de https://. Además, el modelo de programación que debe utilizarse es basado en eventos, dichos eventos alertarán al cliente cuando se realice una conexión con el servidor, cuando ocurra un error, o cuando se reciba un mensaje por parte del servidor. Para crear un websocket, se debe ingresar la dirección del servidor web con el esquema “ws://” o “wss://” y especificar alguno de los subprotocolos soportados en la especificación de websockets (ver: http://www.iana.org/assignments/websocket/websocket.xml).

Después de abrir una conexión con el servidor, el cliente puede enviar mensajes con la función “send” que se encuentra definida en la referencia a la conexión creada anteriormente. Los datos que se pueden enviar pueden ser cadenas de texto o datos binarios representados con los objetos Blob o ArrayBuffer. Un ejemplo del uso de websockets desde el lado del cliente podría ser el siguiente.

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
connection.onopen = function () {
  connection.send('Hello Server!'); // Send the message 'Ping' to the server
};

connection.onerror = function (error) {
  console.log('WebSocket Error ' + error);
};

connection.onmessage = function (e) {
  console.log('From Server: ' + e.data);
};

connection.send('Hello cutty server!');

var img = canvas_context.getImageData(0, 0, 200, 200);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
connection.send(binary.buffer);

var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

En el ejemplo anterior se ha creado una conexión con el servidor utilizando la clase WebSocket, la cual se encuentra disponible en la mayoría de navegadores modernos. La instancia creada de dicho objeto es utilizada para declarar una serie de funciones de callback que serán invocadas cuando se produzcan diferentes tipos de eventos posibles.

Por otro lado, aunque se trata de una tecnología muy interesante y que se comienza a utilizar con mayor frecuencia en aplicaciones web, no obstante la principal dificultad a la hora de utilizar websockets, es la imposibilidad de establecer conexiones utilizando servidores proxy por medio y dado que en la mayoría de entornos empresariales, el uso de servidores proxy es bastante común, nos encontramos con una limitación que hay que tener en cuenta cuando se habla de utilizar WebSockets en aplicaciones web. La razón de esto, es que los WebSockets utilizan el valor “upgrade” para la cabecera “Connection” o directamente la cabecera “Upgrade” con el el valor “WebSocket” y dicho valor indica que la conexión que inicialmente se ha establecido utilizando HTTP, debe “actualizarse” para utilizar sockets del tipo TCP. Este tipo de cambios en las conexiones no son soportados por los servidores proxy del tipo HTTP, ya que están diseñados para trabajar con paquetes de datos que utilizan el protocolo HTTP, en este caso, la conexión es automáticamente cortada por el servidor. Para “mitigar” este problema existen varias soluciones, como por ejemplo el uso del proyecto Apache Camel (http://camel.apache.org) o mi favorita, el uso de “mod_proxy_wstunnel” (ver: http://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html) sobre esta extensión de Apache os hablaré en una próxima entrada.

Hasta este punto se ha hablado del lado del cliente, sin embargo en el lado del servidor se requiere un cambio de enfoque muy importante, ya que ahora hablamos de que el servidor debe soportar múltiples conexiones abiertas al mismo tiempo, con el consecuente consumo de recursos que aquello implica, por éste y otros motivos, la mayoría de servidores web modernos soportan modelos “Non-bloquing IO” o lo que es lo mismo, varios grupos de hilos que se ejecutan de forma concurrente y asíncrona para el procesamiento de respuestas. Se trata de un modelo de arquitectura de software ampliamente aceptado y utilizado hoy en día, tanto en servidores como en sistemas operativos. Alguno de los servidores web que soportan estas características (sin ser una lista exhaustiva y basándome únicamente en los que he probado) se mencionan a continuación.

Apache Web Server 2.2 / 2.4 (http://httpd.apache.org/)

Jetty (http://www.eclipse.org/jetty/)

Apache Tomcat (http://tomcat.apache.org/)

JBoss (http://www.jboss.org/)

Socket.IO (http://socket.io/)

Pywebsocket para Apache web Server. (http://code.google.com/p/pywebsocket/)

Tornado (https://github.com/tornadoweb/tornado)

Vulnerabilidades comunes en el uso de websockets

Ahora que está claro qué son y para qué sirven los websockets, es el momento de hablar sobre las vulnerabilidades que se pueden producir cuando se implementan de forma indebida o con pocos controles sobre los datos intercambiados entre cliente y servidor. Estamos hablando de una tecnología joven, que si bien tiene un potencial enorme a la hora de crear aplicaciones web robustas, esto no es gratis y tiene sus riesgos. Algunos de dichos riesgos se explican a continuación.

Transporte no securizado y vulnerable a ataques MITM.

Como se ha mencionado anteriormente, los websockets funcionan utilizando el protocolo TCP, lo que habilita muchas posibilidades a la hora de realizar conexiones contra multitud de servicios, sin embargo si el canal de comunicación no se encuentra debidamente securizado, un ataque del tipo MITM puede comprometer todos los mensajes enviados entre cliente y servidor. Siempre es una buena practica utilizar el contexto “wss://” para establecer conexiones cifradas con TLS.

Los websockets no soportan autenticación ni autorización.

El protocolo de websockets no soporta los mecanismos tradicionales de autenticación y autorización. Es un asunto relacionado con la implementación propiamente dicha del protocolo y en el caso de que el cliente y el servidor intercambien información sensible, además de securizar el canal de comunicación utilizando TLS, también es recomendable utilizar mecanismos de autenticación basados en tokens/tickets. Dichos mecanismos son bastante populares en implementaciones REST, donde algunos servicios solamente pueden ser consumidos si el cliente cuenta con un token de autenticación valido y dicho token se vincula con el servidor por medio de una cuenta de usuario. Dicho patrón de autenticación se ha vuelto cada vez más popular y en aplicaciones que utilizan websockets que requieren mecanismos de control sobre los usuarios autenticados, es una excelente forma de mantener un control de acceso a recursos sensibles.

Validación en los datos de entrada

Aunque los websockets utilicen TCP para realizar las conexiones entre clientes y servidores, aun nos encontramos en el contexto de una aplicación web y es importante validar los datos de entrada de los usuarios. En el caso de no validar los campos de entrada adecuadamente, se pueden producir vulnerabilidades del tipo XSS aunque para la comunicación se ha un protocolo distinto a HTTP.

Vulnerabilidades Cross Site Request Foregy

Tal como se comentaba en un articulo anterior, las políticas de “same origin policy” que aplican cuando se trata de compartir recursos entre distintos dominios, ahora ya no son tan estrictas cuando se utiliza la cabecera HTTP “Origin”. Tal como se mencionaba en dicho articulo, se trata de una característica que está muy bien cuando se trata de compartir recursos con dominios “fiables” y cuando hablamos de relaciones de confianza en el mundo de la seguridad de la información, siempre pueden haber situaciones que le permiten a un atacante abusar de dichas condiciones.

Los websockets no están limitados a las restricciones de SOP, esto significa que un atacante puede iniciar una petición websocket desde su sitio web malicioso contra un endpoint (ws:// o wss://) de una aplicación web aunque no se encuentre en el mismo dominio. Esto tiene unas implicaciones tremendas, ya que el handshake que ejecutará el cliente para iniciar una petición WebSocket es una petición HTTP regular y los navegadores enviarán las cookies y cabeceras HTTP de autenticación aunque se trate de un dominio cruzado, si y sólo si, el servidor web no valida adecuadamente la cabecera “Origin”.
Para que el lector se haga una idea del problema, supongamos que la víctima ha iniciado sesión en un sitio web que tiene uno o varios endpoints “ws” o “wss” y en una pestaña nueva del navegador, ingresa en una página web maliciosa controlada por el atacante. Dicha página podría realizar una petición WebSocket contra el sitio web en el que el usuario se encuentra identificado y si dicho sitio web, no valida adecuadamente el valor de la cabecera “Origin”, la respuesta a la petición del atacante podrá contener, entre otras, las cookies y cabeceras de autenticación utilizadas por el usuario, sin importar que se trate de un dominio cruzado. Esta situación puede dar lugar a una vulnerabilidad del tipo CSRF.

En un próximo articulo, hablaré un poco más sobre cómo explotar algunas de las vulnerabilidades que se han listado aquí.

Saludos y Happy Hack!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: