viernes, 18 de octubre de 2013

Solución al problema de seguridad CSRF en Apache Tapestry

Apache Tapestry
Al desarrollar una aplicación el problema de seguridad XSS (Cross-site scripting) puede afectar a los usuarios de nuestra aplicación. XSS consiste en que la aplicación permite la inyección de código malicioso que posteriormente otros usuarios obtienen al acceder a nuestra aplicación. Se produce porque nuestra aplicación no realiza el escapado correctamente de lo que envía al usuario y porque el usuario confía en lo que obtiene del servidor. Para evitar este problema Apache Tapestry por defecto realiza un escapado de lo que emite al cliente con lo que si no hacemos lo contrario la aplicación estará a salvo de este problema.

Otro problema de seguridad es CSRF (Cross-site request forgery) en el que básicamente un sitio al que se accede devuelve un enlace malicioso que provoca una acción en otro, el atacado. El enlace devuelto puede producir cualquier acción que el sitio atacado permita, el ejemplo que se suele poner es el de un sitio bancario y el intento de hacer una transferencia de la cuenta del usuario que tiene iniciada una sesión en la página de su banco a la cuenta del atacante pero podría ser la realización de un cambio de contraseña a una que conozca el atacante y de esta forma posteriormente este pueda autenticarse con la cuenta de ese usuario en el sitio atacado. En la wikipedia este problema de seguridad está más ampliamente explicado con ejemplos, limitaciones y como prevenirlo. A diferencia de XSS donde el usuario confia en lo que obtiene del servidor en el caso de CSRF es al contrario, el servidor confia en las peticiones del cliente, aunque puedan provenir de un sitio malicioso.

Una solución que suele aplicarse para resolver el problema de CSRF es incluir en los enlaces y formularios un token de seguridad, si el token no se envía o no se corresponde con el token del servidor la petición se considera inválida y no se procesa. Al acceder a una página se genera el token de seguridad y se incluye en todos los enlaces y formularios, este token no será conocido por un a tercera parte y los enlaces maliciosos no serán procesados.

En esta entrada mostraré como solucionar este problema en Tapestry con una combinación de mixin, anotación, advice y objeto de estado de aplicación (SSO), similar a lo explicado en este blog pero con la adición que no solo sirve para formularios sino también para enlaces y el componente BeanEditForm.

Primero veamos el objeto estado de aplicación que contendrá el token (sid) de seguridad, lo generará y lo validará, este objeto de estado de aplicación se guardará a nivel de sesión de modo que el token que se envía en la petición pueda ser validado con el token guardado en este SSO.

El mixin CSRF hará que en los formularios se incluya un campo oculto con el token se seguridad del SSO y en los enlaces se incluya como un parámetro. El nombre del parámetro en ambos casos será t:sid. Este mixin puede ser aplicado a los componentes Form, ActionLink, EventLink y BeanEditForm.

Creamos una anotación para marcar los manejadores de evento y métodos donde queremos que aplique la seguridad CSRF.

Para aplicar la seguridad en los manejadores de evento y métodos marcados con la anotación lo haremos con cierta metaprogramación, con ella comprobaremos que el token del SSO se corresponda con el token enviado por la petición. Esta forma de metaprogramación es lo que en Tapestry se conoce como Advice, la funcionalidad consistirá en si el token de seguridad es correcto se permite la invocación al método protegido, si el token no es correcto se lanza una excepción impidiendo la llamada al método protegido.

Finalmente, debemos modificar el módulo de nuestra aplicación para dar a conocer a Tapestry el Advice para aplicar y comprobar la seguridad con el parámetro t:sid enviado y en el objeto SSO.

Para que en los componentes sea incluido del token de seguridad haremos uso del mixin, es tan simple añadir el atributo t:mixins y el mixin csrf en los elementos a incluir el parámetro t:sid:

Y para proteger los manejadores de evento con la anotación Csrf de la siguiente manera:

Con todo esto podemos resolver el problema de seguridad CSRF de forma muy simple y de forma declarativa con una combinación de mixin y anotaciones, solo son necesarios ¡20! caracteres entre ambos.

Esta es la sección de la aplicación del ejemplo funcionando donde puede probarse el mixin y ver la diferencia del comportamiento sin el mixin aplicado.

Cuando pulsamos en el enlace que envía un t:sid inválido mediante un petición ajax provocará el siguiente informe de error con un mensaje descriptivo de lo que ha ocurrido.


En las siguientes imágenes puede verse el parámetro t:sid que se añade tanto a un formulario como a un enlace cuando le aplicamos el mixin csrf.
Parámetro t:sid en un formulario

Parámetro t:sid en un enlace

¿Ya tienes en cuenta el problema de seguridad CSRF en tus aplicaciones web? ¿Con el framework que uses aplicar una solución es tan simple como esta?

De esta entrada aparte de resolver el problema de seguridad CSRF quiero destacar con se realiza la metaprogramación en Apache Tapestry con las clases Plastic de Tapestry en la clase CsrfWorker.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes como este en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.


Referencia:
Cross-Site Request Forgery (CSRF)
Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet
Apache Tapestry - CSRF Protection - First Prototype
http://wiki.apache.org/tapestry/Tapestry5CSRF
https://code.google.com/p/gsoc2011-csrf-protection