viernes, 31 de mayo de 2013

Seguridad en aplicación web con Apache Tapestry (II)

Apache Tapestry
Si en la anterior entrada hablaba de la seguridad sobre los aspectos de la autenticación y autorización de las acciones que puede realizar los usuarios en una aplicación web en esta hablaré como protegerse de otro tipo de fallos de seguridad, XSS e inyección de Sql.

Otros dos aspectos muy a tener en cuenta desde el inicio y durante el desarrollo de una aplicación web son los siguientes:
  • XSS (Cross site scripting): es una vulnerabilidad que pueden sufrir las aplicaciones por básicamente no controlar los datos que un usuario envía a través de formularios o como parámetros en las URL. Por ejemplo, supongamos una aplicación recibe un formulario con un nombre que se escupe tal cual se envió en otra página de la aplicación y que otros usuarios pueden visualizar en sus navegadores posteriormente cuando accedan a las páginas que los muestran. Una posible situación puede darse cuando los datos enviados se guardan en una base de datos, un usuario los envía se guardan en la base de datos y otro usuario los ve. Ese dato puede ser una cadena inofensiva como el nombre que se pide pero un usuario malicioso puede enviar código javascript o una imagen con una URL que puede recolectar con cualquier propósito la información de los usuario que la ven en su navegador. Un usuario enviando los datos adecuados puede explotar esta vulnerabilidad y conseguir desde obtener la sesión de otro usuario y hacer cualquier tipo de acción como si fuera ese otro usuario, hasta obtener datos y distribuir virus a los usuarios a través de nuestra propia página web. 
  • Inyección Sql: esta vulnerabilidad puede ser explotada también por confiar en los valores que envía el usuario pero en vez afectar al html que genera la aplicación web afecta a las base de datos que utilice la aplicación. Si usamos los parámetros enviados por una fuente no confiable para construir las sql de forma dinámica concatenando trozos de sentencia con los parámetros, un parámetro con el valor adecuado puede modificar completamente la sentencia. Concatenando elementos se puede terminar una Sql y hacer cualquier otra a continuación. Las posibilidades de esto es que se podría extraer cualquier dato o borrar completamente la base de datos con sentencias delete o drop. Por ejemplo, hacer esto tiene el problema de la inyección de Sql: "select * from producto where id = " + id. Si el parámetro id tuviese el valor "1; delete from producto;" podríamos borrar todos los datos de la tabla.
Por tanto, tanto para evitar fallos de seguridad por XSS y de inyección Sql no se debe confiar en ningún dato enviado por el usuario o de un sistema externo. En realidad en ambos problemas de seguridad la situación es el misma pero que afecta a distintas partes de la aplicación, en un caso a la base de datos (inyección Sql) y en otro a la capa de presentación de la aplicación (XSS).

¿Que hay que hacer para evitar estos problemas? Depende del caso. Para evitar XSS todo lo que se emita en el html de la página y se envíe al navegador del usuario ha de ser codificado como html haciendo que si hay un dato malicioso sea inofensivo ya que el navegador no lo interpretará como parte del lenguaje de marcas html sino como texto. Para evitar la inyección de Sql si construimos alguna dinñamicamente los parámetros no se han de añadir concatenándolos. En Java con PreparedStatement, y seguro que en cualesquiera otros lenguajes, por un lado va la sql y por otro los parámetros, la clase o API que utilicemos se encargará de ejecutar la sentencia con los parámetros adecuados sin el problema de la inyección Sql (además tiene la ventaja de que el código será más legible al no estar mezclada con los parámetros concatenados).

A continuación explicaré que funcionalidades proporciona Tapestry para que las aplicaciones desarrolladas con él sean más seguras en cuanto a XSS.

Para evitar XSS todo lo que se genere como html a partir de datos recuperados de la base de datos y enviados por un usuario hay que escaparlo. Y Tapestry hace eso por defecto por lo que salvo que de forma expresa no hagamos el escapado no tendremos problemas de XSS. La generación de html se puede hacer de dos formas: en los archivos de plantilla tml o en código Java si se trata de un componente que no tiene plantilla tml asociada.

Con una plantilla tml haremos lo siguiente y el nombre se mostrará escapado en el html:

Para evitar escapado hay que usar la opción:

En el componente Java usaremos la clase MarkupWriter y su método write para escapar los valores y el método writeRaw para evitar el escapado si estamos seguros de que no implica un problema de seguridad:

Para evitar inyección de Sql usando Hibernate, JPA o la clase PreparedStatement y separando los parámetros de la sql o hql estaremos protegidos. Las buenas prácticas y un ejemplo de mala práctica usando la API de Hibernate, hql y sql para hacer las búsquedas son las siguientes:

En la siguiente imagen puede verse como se puede inyectar javascript enviando un formulario con dato que no es escapado correctamente al mostrar su valor de nuevo.

Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada previamente (salvo java y git). Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace.

Referencia:
Documentación sobre Apache Tapestry
Cross site scripting
Inyección SQL
MarkupWriter
Output
OutputRaw