Seguridad en sitios web para webmasters

A los usuarios se les enseña a protegerse de programas maliciosos mediante la instalación de programas antivirus sofisticados pero, a veces, también confían sus datos personales a sitios web como el tuyo, en cuyo caso es importante proteger sus datos. Proteger tus propios datos también es importante. Si tienes una tienda online, no querrás que te roben.

A lo largo de los años, las empresas y los webmasters han aprendido (a menudo por las malas) que la seguridad de las aplicaciones web no es ninguna broma. Hemos visto fugas de contraseñas debidas a ataques de Inyección SQL, robo de cookies con XSS y sitios web vulnerados por hackers debido a negligencias en la validación de los datos de entrada.

Hoy os mostraremos algunos ejemplos de cómo se puede atacar una aplicación web, para que puedas aprender de ello. Con este fin, usaremos Gruyere, una aplicación intencionadamente vulnerable que también usamos internamente para formación sobre seguridad. No pruebes la vulnerabilidad de los sitios web de otras personas sin su permiso, puesto que podría considerarse un ataque (hacking), pero te damos la bienvenida (e incluso te animamos) a hacer pruebas en Gruyere.

Manipulación del estado del cliente (Client State): ¿qué sucede si altero la URL?

Imaginemos que tienes un sitio de alojamiento de imágenes y que usas una secuencia de comandos en PHP para mostrar las imágenes subidas por los usuarios.

http://www.example.com/showimage.php?imgloc=/garyillyes/kitten.jpg

Pues bien, ¿qué sucederá si cambio la URL por algo así y userpasswords.txt es un archivo de verdad?

http://www.example.com/showimage.php?imgloc=/../../userpasswords.txt

¿Obtendré el contenido de userpasswords.txt?

Otro ejemplo de manipulación de estado del cliente se produce cuando no se validan los campos de los formularios. Por ejemplo, imaginemos que tienes este formulario:



Parece que el nombre de usuario del remitente se almacena en un campo oculto. Bueno, ¡esto es genial! ¿Significa que si cambio el valor de ese campo por el de otro nombre de usuario puedo enviar el formulario como si fuese ese otro usuario? Bien podría suceder. Aparentemente, los datos introducidos por el usuario no se autentican con, por ejemplo, ningún token que se pueda verificar en el servidor.
Imagina la situación si ese formulario formase parte de un carrito de la compra y modificásemos el precio de un artículo de 1000 USD por 1 USD para, después, enviar el pedido.

Proteger tu aplicación frente a este tipo de ataques no es fácil. Echa un vistazo a la tercera parte de Gruyere [inglés] para ver algunos consejos sobre cómo defender tu aplicación.

Cross-site scripting (XSS): los datos introducidos por el usuario no son de fiar


Una URL simple e inofensiva:
http://google-gruyere.appspot.com/611788451095/%3Cscript%3Ealert('0wn3d')%3C/script%3E
¿Es realmente inofensiva? Si descodificamos los caracteres codificados con el signo de porcentaje, obtenemos:

<script>alert('0wn3d')</script>

Al igual que muchos sitios web con páginas de error personalizadas, Gruyere está diseñada para incluir el componente de la ruta dentro de la página HTML. Esto puede generar problemas de seguridad, como XSS, puesto que introduce el código introducido por el usuario tal como está en la página HTML de la aplicación web. Podríamos pensar, "bueno, es solo un cuadro de advertencia, ¿y qué?". El problema es que si puedes inyectar un cuadro de advertencia, puedes, con toda probabilidad, inyectar otra cosa, también, y tal vez aprovechar para robarte las cookies y usarlas para acceder a tu sitio como si fueses tú.

Otro ejemplo es cuando no se limpian las entradas del usuario. Imaginemos que escribo un comentario en tu blog. Se trata de un comentario muy simple:

<a href=”javascript:alert(‘0wn3d’)”>Click here tos see a kitten</a>

Si otros usuarios hacen clic en mi inocente enlace, tendré sus cookies:



Puedes ver cómo resolver las vulnerabilidades por XSS en tu propia aplicación web e intentar resolverlas en la segunda parte de Gruyere [inglés] o, si eres un desarrollador avanzado, mirar las características sobre escapado automático en sistemas con plantillas de la que hablamos en nuestro blog sobre seguridad online [inglés].

Falsificación de petición en sitios cruzados (XSRF): ¿debería aceptar las solicitudes procedentes de diablos.com?

Oh, vaya, una imagen rota. No puede ser peligrosa: está rota, al fin y al cabo, lo cual significa que la URL de la imagen devuelve un código 404 o tiene un formato incorrecto. ¿Pero es siempre así?

¡No! La fuente de una imagen se puede especificar con cualquier URL, sea cual sea su tipo de contenido. Puede ser una página HTML, un archivo JavaScript, u otro recurso potencialmente malicioso. En este caso, la fuente es la URL de una simple página:



Esta página sólo funcionará si tengo una sesión iniciada y algunas cookies asignadas. Puesto que realmente tenía una sesión iniciada en la aplicación, cuando el navegador ha intentado recuperar la imagen accediendo a la URL de fuente, también ha eliminado mi primer fragmento. Esto no suena particularmente peligroso, pero si conozco un poco la aplicación también podría invocar una URL que elimine el perfil de un usuario o permita a un administrador otorgar permisos a otros usuarios.

Para proteger tu aplicación de XSRF no deberías permitir nunca que las acciones de cambio se soliciten vía GET. El método POST se inventó para este tipo de peticiones de cambio de estado. Este cambio por si solo podría mitigar el ataque anterior, pero por lo general no basta y es necesario añadir algún valor impredecible a todas las solicitudes que supongan un cambio de estado para prevenir las acciones de XSRF. Si quieres más información sobre XSRF puedes ir directamente a Gruyere [inglés].

Inclusión de Cross-site script (XSSI): todas tus secuencias de comandos nos pertenecen

En muchos sitios es posible actualizar dinámicamente el contenido de una página mediante peticiones de JavaScript asincrónicas que devuelven datos JSON. A veces JSON puede contener datos sensibles que, si no se toman las precauciones debidas, un hacker podría robar.

Imaginemos la situación siguiente: hemos creado una páginas HTML estándar y te enviamos el enlace. Puesto que confías en nosotros, visitas el enlace que te hemos enviado. La página contiene tan solo unas cuantas líneas:

<script>function _feed(s) {alert("Your private snippet is: " + s['private_snippet']);}</script>

Puesto que has iniciado sesión en Gruyere y dispones de un fragmento privado, verás un cuadro de alerta en mi página que te informa sobre el contenido de tu fragmento. Como siempre, si nos las hemos arreglado para abrir un cuadro de alerta, podremos hacer lo que queramos. En este caso se trata de un simple fragmento, pero también podría haber sido tu mayor secreto.

Defender a una aplicación frente a XSSI no es demasiado difícil, pero exige pensar con cuidado. Puedes usar tokens, tal como se explica en la sección sobre XSRF, hacer que tu secuencia de comandos solo responda a peticiones POST o simplemente iniciar la respuesta JSON por "\n" para asegurarte de que la respuesta no es ejecutable.

Inyección de SQL: ¿todavía crees que lo que introducen los usuarios es seguro?

Qué sucedería si intento acceder a tu aplicación con un nombre de usuario como

MarioMartinez' ; DROP TABLE members;--

Aunque este ejemplo en particular no dejaría expuestos los datos de los usuarios, podría provocar grandes quebraderos de cabeza porque tiene la capacidad de eliminar por completo la tabla de SQL en la cual tu aplicación almacena los datos de los miembros registrados.

Por lo general, puedes proteger a tu sitio web de la inyección de código SQL pensando proactivamente sobre la introducción de datos de los usuarios En primer lugar: ¿estás seguro de que tu usuario de SQL necesita disponer de permiso para ejecutar "DROP TABLE members"? ¿No bastaría con concederle derechos de SELECT? Asignando los permisos de los usuarios cuidadosamente puedes evitar experiencias dolorosas y un montón de problemas. También puede ser útil configurar los informes de error de tal modo que no queden expuestos los nombres de las bases de datos ni de las tablas en caso de que una consulta falle.

En segundo lugar, tal como hemos aprendido en el caso XSS, los datos introducidos por el usuario no son nunca de fiar. Lo que para ti parece un formulario de inicio de sesión, es una posible puerta de acceso para un atacante. Limpia y verifica siempre la estructura de la información de entrada que se vaya a almacenar en una base de datos y, siempre que sea posible, usa instrucciones del tipo de consultas preparadas o parametrizadas, disponibles en la mayoría de las interfaces de programación de bases de datos.

Sabiendo cómo es posible atacar una aplicación web es el primer paso para entender cómo protegerla. Por este motivo, te animamos a que sigas el curso de Gruyere [inglés], aproveches otros cursos sobre seguridad web disponibles en la Google Code University [inglés]. También puedes probar Skipfish [inglés], una herramienta de prueba automática de la seguridad. Si tienes alguna pregunta más, no dudes en enviarla a nuestro Foro de ayuda para webmasters.

viernes, 8 de julio de 2011