Que las aplicaciones web que desarrollas funcionen y sean escalables es importante, pero mucho más lo es que sean seguras de forma que no se vea comprometida la seguridad y privacidad de tus usuarios. En este artículo damos un repaso a los ataques más comunes y cómo defenderte de ellos.

Autor:

Intentando mejorar cada día en este mundo tan cambiante de la programación. Sígueme en Twitter o en GitHub. Actualmente estoy disponible para contratar.

Introducción

Antes de ponerme a comentar los distintos tipos de vulnerabilidades conocidos y explotados de las aplicaciones web, quiero compartir el siguiente informe: Informe de Investigación de Datos Violados 2010 (el informe se genera en 2010, por lo que analiza el año 2009) creado por Verizon en colaboración con el USSS (United States Secret Service).

Es un informe muy completo que analiza en profundidad los distintos tipos de ataques llevados a cabo con el objetivo final de robar información, bien sea a corporaciones o particulares. Os dejo un par de datos que me han parecido relevantes:

  • 40% de los robos fueron por hacking.
  • 98% de los datos robados, procedían de servidores.
  • 85% de los ataques fueron considerados fáciles.
  • 96% de los robos serían evitables con medidas simples o intermedias.

Solamente con ver estes datos, uno tiene razones más que suficientes para ponerse al día en el tema de seguridad web, y eso es lo que intentaré hacer en este artículo. A continuación le echamos un vistazo a los tipos de ataques más comunes para que por lo menos sepas que existen y los analices más profundamente si lo consideras necesario. Pero antes, os dejo unas cuantas gráficas extraídas del informe:

Categorías de ataques por porcentaje de robos y registros

Tipos de hacking por porcentaje de robos y registros

Vías de ataque por porcentaje de robos y porcentaje de filas

Cross-Site Scripting (XSS)

Es un tipo de vulnerabilidad web que permite a personas malintencionadas insertar código de lado de cliente (Javascript, VBScript, Flash…) en las páginas web accesibles por el resto de usuarios. Debido a esto, un atacante podría conseguir acceso a contenido sensible, cookies de sesión y demás información que el navegador almacene sobre el usuario atacado.

Un posible uso de esta vulnerabilidad, sería ejecutar un código Javascript que obtenga la cookie que almacena el identificador de sesión (SID) y lo envía al atacante, pudiendo así usar esa cookie para suplantar al usuario afectado.

Hay una pequeña categorización de este tipo de ataques, que los divide en dos:

A través de XSS una persona malintencionada puede insertar código en una web, de forma que cualquier usuario que entre, estará expuesto a sus peligros.

No persistente

Este es el tipo más común y se produce cuando un usuario envía datos al servidor, normalmente a través de la Query String (GET) o de un formulario (POST) e inmediatamente el código del servidor genera una respuesta usando esa misma información sin limpiar adecuadamente los datos.

Por ejemplo imagina que has programado un buscador para tu sitio web, que cuando no encuentra lo que acabas de buscar, genera una salida como “No se ha encontrado nada sobre gatos” en el caso que hayas buscado la palabra “gatos”. Bien, esto parece algo inofensivo pero…y si busco el siguiente texto?:

<script>alert(1)</script>

Pues que el servidor generará la siguiente salida:

No se ha encontrado nada sobre <script>alert(1)</script>

De forma que el navegador, al encontrarse con la etiqueta <script>, ejecuta inmediatamente el código, en este caso, saltaría un inofensivo cuadro de diálogo.

A lo mejor ahora te estás preguntando, “¿pero cómo afecta esto a un usuario particular?”, “nadie que no sepa del tema, va a buscar eso y en cualquier caso, se está fastidiando a sí mismo”. Bien, imagina que tu buscador maneja las peticiones a través de parámetros GET de forma que si buscas “gatos”, accedes a la siguiente dirección:

http://example.com/search?q=gatos

Pues alguien malintencionado, puede generar la url:

http://example.com/search?q=<script>alert(1)</script>

Simplemente tendría que enviar la URL a las personas que desea y listo.

Persistente

Este es un tipo más devastador ya que puede llegar a afectar a cualquier usuario que entre en tu web. Se trata de insertar y almacenar código malicioso en el servidor, de forma que se muestre a cualquier persona que acceda a dicha página. Esto es muy fácil de conseguir en las aplicaciones web que permiten a los usuarios generar contenido, como envíar comentarios, dar opinión en foros, etc…

Imagina que unos foros muy visitados no están limpiando bien los textos que los usuarios envían. Una persona que se haya dado cuenta, podría enviar un simple mensaje con:

<script>alert(1)</script>

Ahora, cada persona que visite la página en la que has escrito, verá un inofensivo cuando de texto. Pero repito, podría ejecutar cualquier código, tan malicioso como uno quiera y la seguridad del navegador lo permita.

La diferencia entre persistente y no persistente es que en los ataques persistentes, el código queda almacenada en el lado del servidor, mostrándose y ejecutándose en cada petición, mientras que los ataques no persistentes, inyectan el código de forma temporal como respuesta a una petición específica.

Cómo protegerse

  • Asegúrate de que todas las salidas generadas con textos potencialmente inseguros (enviados por usuarios) son completamente escapados. Para eso PHP nos ofrece algunas funciones como htmlentities o htmlspecialchars, o como habíamos visto en un tutorial anterior, puedes Validar y sanear datos en PHP de forma bastante sencilla.
  • Como ya he comentado, el principal objetivo de este tipo de ataques, es el robo de las cookies. Muchos sitios web, evitan que un atacante pueda suplantar cookies de otros usuarios vinculando la cookie a la dirección IP para la cual se había creado. De esta forma, alguien que intente usar una cookie desde otro ordenador, será considerado un usuario malicioso y se ignorará la cookie. Tambien existe la opción de especificar una cookie como HttpOnly, de forma que los navegadores no permiten acceder a dicha cookie al código ejecutado en el lado de cliente. Esta opción es soportada prácticamente por todos los navegadores modernos.

Cross-site request forgery (CSRF o XSRF)

Esta vulnerabilidad explota la confianza que un sitio tiene un usuario, a diferencia del XSS, que explota la confianza que un usuario tiene en un sitio web. A grandes rasgos, consiste en que una persona malintencionada envía un link a una persona que sabe (o supone) que está identificada en una web, de forma que la persona ejecuta ciertos comandos sin enterarse.

Por ejemplo, imagina una web de un banco que dispone de la siguiente url para realizar una transacción:

http://example.com/transaction?to=[ID USUARIO]&amount=[CANTIDAD]

Sería realmente sencillo generar una url para que cualquier usuario identificado, te enviase dinero. Sería tan fácil como enviarle este link:

http://example.com/transaction?to=ivan&amount=1000

Ahora, imagina que en ese banco existen unos foros para que los usuarios registrados puedan opinar sobre distintos temas. Si no tienen los textos perfectamente saneados y escapados, una persona malintencionada podría insertar la siguiente etiqueta HTML:

<img src=”http://example.com/transaction?to=ivan&amount=1000” />

De esta forma, el navegador de cualquier usuario que entra en el foro, intentará descargar dicha imagen, pero en realidad, esa url no va a generar ninguna imagen, lo que va hacer es enviar una orden de transacción en caso de que el usuario esté identificado. Como ya he dicho, es un exceso de confianza del sitio web en las acciones del usuario.

Cómo protegerse

  • Requerir una clave secreta al usuario antes de llevar a cabo cualquier acción comprometida, como sería el caso del ejempl anterior.
  • Limitar el tiempo de vida de la sesión: lo hacen en muchas webs de contenido sensible.
  • Deshabilitar la opción de “Recordarme” ayuda a prevenir este tipo de ataques: si activas esa opción y luego te envían un exploit de CSRF, tienes muchas más posibilidades de que te afecte, pues el no estar logueado no te salva, ya que iniciarás la sesión automáticamente, ejecutando la acción que el exploit te envía.
  • Comprobar la cabecera Referer: cualquier petición que no contenga esta cabecera debe ser denegada, debido a que existen formas sencillas de evitar el envío de esa cabecera. Además, esta validación podría tener problemas con navegadores o proxies que evitan el envío de esta cabecera por razones de privacidad. Sin embargo, si el sitio web requiere de máxima seguridad, es una opción más a tener en cuenta.
  • Usar GET y POST debidamente: según los estandares, las peticiones GET nunca deben de tener efectos permanentes. Si bien los envíos POST tambien se pueden falsear, es una tarea más complicada en la que tienen que darse más vulnerabilidades.

SQL injection

Es un tipo de ataque que explota la vulnerabilidad de la capa de base de datos de una aplicación. Se presenta cuando los filtros pasados a una sentencia SQL no son escapados correctamente y por lo tanto, un usuario malitencionado puede envíar caracteres con significado especial en SQL para modificar la consulta.

En 2009, el 25% de los robos a través de hacking, fueron hechos usando SQL injection.

Imagina la siguiente consulta SQL para comprobar que los datos de inicio de sesión que acaba de enviar un usuario son correctos:

$query = “SELECT * FROM users WHERE login='{$username}' AND password='{$password}'”;

Si las variables son recibidas directamente del formulario enviado y no son escapadas, un usuario malintencionado podría hacer envíar lo siguiente:

  • Usuario: ivan
  • Contraseña: ‘ or ’1′=’1

Así, la query resultante sería:

SELECT * FROM users WHERE login='ivan' AND password=' ' or '1'='1' ;

Lo cual, hace que la condición siempre sea cierta y te puedas identificar como cualquier usuario.

La inyección SQL tiene muchas posibilidades, ya que una persona con experiencia podría poco a poco investigar la base de datos y llevar a cabo tareas como robar información valiosa, eliminar tablas importantes con el objetivo de hacer daño a tu sitio web, insertar contenido malicioso, dar permisos de administrador a su usuario…entre otras muchas, hay tantas posibilidades como ideas maliciosas :)

A continuación dejo un ejemplo para mostrar lo sencillo que es eliminar una tabla de un sitio web vulnerable a inyección SQl, para que te tomes siempre muy en serio este tipo de vulnerabilidad.

Siguiendo con el caso anterior, un usuario podría rellenar el formulario con lo siguiente:

  • Usuario: ivan
  • Contraseña: ‘;DROP TABLE users; –

Por lo que la consulta resultante sería:

SELECT * FROM users WHERE login='ivan' AND password=' ' ;DROP TABLE users; –';

Más vale que tuvieses bien configuradas las copias de seguridad :)

Como protegerse

Una vez más, la solución es escapar los datos antes de incrustarlos en la consulta. En PHP disponemos de una función llamada mysql_real_escape_string limpiará todos los caracteres que tienen significado especial para MySql y pueden modificar la consulta. Por lo tanto, la consulta de inicio de sesión que hemos visto, se corregiría ejecutándola de este modo:

$userName = mysql_real_escape_string($userName);
$password = mysql_real_escape_string($password);
$query = sprintf(“SELECT * FROM users WHERE login='%s' AND password='%s'”, $userName, $password);

También os podéis currar vuestro propio código para gestionar las consultas y que sea más cómodo. En un tutorial ya habíamos visto Cómo crear una capa de conexión abstracta a la base de datos

Session Fixation

Este ataque se aprovecha de la vulnerabilidad de algunos sitios que permiten a un usuario fijar el identificador de sesión (SID) de otro usuario. La mejor forma entender esta vulnerabilidad es mediante un ejemplo (usados los nombres por convención)

  • Un usuario malintencionado llamado Mallory se percata de que en el sitio http://vulnerable.com existe la posibilidad de cambiar el SID de los usuarios.
  • Mallory, envía el siguiente link a Alice: http://vulnerable.com?SID=este_sera_tu_sid (con esto lo que hace es que cuando Alice entre en el sitio web, el servidor establecerá su SID con el valor “este_sera_tu_sid”, de forma, que Mallory sabe el SID de Alice).
  • Alice entra confiada en la web e inicia sesión.
  • Mallory, al conocer el SID de un usuario identificado en la web, puede suplantarlo simplemente accediendo a http://vulnerable.com?SID=este_sera_tu_sid

Como puedes comprobar, es muy sencillo el proceso.

Cómo protegerse

La primera norma para evitar esto es no aceptar nunca identificadores de sesión a través de variables GET / POST. La mejor forma de manejar los SID de los usuarios es a través de cookies. Si usas PHP puedes configurarlo para que automáticamente maneje las sesiones a través de cookies e ignore cualquier forma de establecer el SID a través de otros medios. Esto se puede hacer configurando lo siguiente en el fichero php.ini:

session.use_cookies = 1
session.use_only_cookies = 1

Otra medida para evitar la fijación de sesión, es regenerar el SID del usuario en cada petición. Haciendo esto, incluso aunque un atacante obtenga tu SID, el SID será inválido cuando el atacante intente suplantar al usuario. Esto es muy fácil hacerlo en PHP, simplemente hay que llamar a la función session_regenerate_id

Conclusión

Como habrás podido comprobar, las aplicaciones web están expuestas a múltiples vulnerabilidades que podrían tener efectos catastróficos. El simple envío de un comentario “infectado” podría tener como resultado el robo de información de cientos o miles de usuarios.

De todas formas, el objetivo de este tutorial no es el de sembrar el miedo entre los desarrolladores, sino el de informar sobre algo que (creo) muchas veces se obvia o se deja en segundo plano. Lo único que hay que hacer es investigar y aprender, si quieres derrotar a tu enemigo, ¡conócelo! :)

Te sugerimos otras entradas relacionadas...

¿Necesitas desarrollar un proyecto web o para móviles? ¡Estamos disponibles!

Visitar Cokidoo

Cokidoo, los creadores de Ontuts, desarrollamos proyectos tecnológicos centrados en redes sociales y aplicaciones web, aplicaciones móviles y consultoría web y bases de datos.

Somos jóvenes, inquietos, versátiles, apasionados por la innovación y enfocados en las nuevas tecnologías. Con Ontuts tratamos de compartir nuestro conocimiento adquirido en los distintos proyectos, ayudando a la comunidad y mostrando nuestra capacidad tecnológica.

Si necesitas un presupuesto sin compromiso, estamos disponibles, no dudes en contactar con nosotros.

Comentarios en esta publicación (8 comentarios)

¿Te ha gustado esta publicación? ¡Puedes compartir tu opinión con todos nosotros! Simplemente pincha aquí mismo.

Lugorcorp

Esto es como recordar tu vida y darte cuenta de esos errores que nunca viste O_O de ahora en adelante tendré más cuidado en la programación!!

bertinillo

alert(1) seria de plano que no tuviera seguridad jajaja, excelente trabajo es de los mejores relacionados del temas, bueno es el unico que resolivio todas mis dudas

NightMare
me da curiosidad

En mi pagina no funciona por que? puse el mensaje este
alert(1)
tengo en mi index.php un echo por ejemplo
index.php?proceso=”hola”
y sustituyo con
index.php?proceso=”alert(1) ” y no funciona
oO como le hago para que el javascript interaccione con el php, por lo que veo no son compatibles, y lo ocupo para mi web,. por que cuando lo uso junto no funciona :(