Seguridad en Aplicaciones Web (IV)

En el artículo anterior analizamos la implementación de ModSecurity en Apache y cómo puede ayudarnos a proteger nuestras aplicaciones web.

En esta parte, analizaremos tres técnicas que podemos utilizar para mitigar los ataque de Denegación de Servicio (DoS) y Denegación de Servicio Distribuída (DDoS).

Características de los DoS y DDoS

Ambos tipos de ataque (DoS y DDoS) suelen causar muchos problemas a las infraestructuras informáticas actuales, debido a que son relativamente sencillos de lanzar y pueden causar que las aplicaciones dejen de responder o lo hagan de una forma realmente lenta.

Para realizar estos ataques, lo más habitual es que se realicen una cantidad enorme de peticiones a la aplicación al mismo tiempo desde uno (DoS) o varios equips (DDoS).

Por su naturaleza distribuída, los ataques DDoS son más difíciles de bloquear, porque el ataque viene desde varios frentes, aunque las IP que realizan el ataque suelen ser bastante evidentes y, con las herramientas adecuadas, se las puede bloquear.

Abajo podemos ver un pequeño gráfico que compara los ataques DoS con los ataques DDoS:

dos_vs_ddos

Recursos de Red

En el caso de los ataques que consumen todos los recursos de red de una aplicación, no suele ser redituable realizar el filtrado a nivel de servidor, porque, cuando el tráfico llega al servidor, ya ha ocupado los recursos de red. En esta situación, el filtrado de las peticiones simplemente aliviana el tráfico que saldría del servidor en el caso de que las peticiones no fueran bloqueadas, pero el tráfico entrante sigue siendo consumido.

Para estos casos, la única protección posible queda en manos de los proveedores de internet (ISP) que deberían tener tecnologías para proteger a sus clientes de este tipo de ataques (aunque la mayoría no cuentan con estas tecnologías)

Recursos de Hardware

Los ataques que consumen los recursos de hardware pueden tener diferentes métodos de funcionamiento. Generalmente, pueden abusar de lo siguiente:

Una aplicación mal programada: En este caso, el atacante podría abusar de ciertas deficiencias de la aplicación, que la harían consumir una cantidad excesiva de recursos. Para esto, la única solución es revisar el código fuente de la aplicación y optimizarlo.

Una tarea que consume mucha capacidad de cómputo: Las tareas de la aplicación que consuman mucha capacidad de cómputo, deberían ser preferentemente cacheadas y accesibles únicamente por usuarios autenticados. Pero esto va a depender del propósito de la aplicación.

Un fallo en el software de servidor: Ciertos ataques DoS pueden ser completados enviando únicamente una petición especialmente manipulada, que el servidor no puede interpretar correctamente. Para esto, debemos mantener siempre nuestros componentes de software actualizados. En estos casos, un Web Application Firewall también puede ayudarnos, bloqueando las peticiones “raras”.

Una cantidad enorme de peticiones: Este caso es el más habitual, y se explota enviando una cantidad de peticiones tan grandes que, aunque la aplicación esté optimizada, termina cediendo. Para estos casos serán de especial utilidad las medidas de protección que listaremos a continuación.

Servidores Distribuídos

Si estamos en presencia de una aplicación que recibe muchas peticiones y requiere unos altos niveles de disponibilidad, es recomendable la implementación de una infraestructura distribuída, que balancee la carga entre distintos proveedores de servicio y, si es posible, diferentes regiones geográficas. Para esto son muy útiles los servicios de computación en la nube (como Amazon AWS y RackSpace).

Aquí, dependiendo de cómo esté desarrollada la aplicación, será más fácil y más difícil distribuir la infraestructura. Porque no todas las apliciones soportan nativamente el balanceo de carga. Aunque todas las aplicaciones web modernas deberían ser desarrolladas pensando en que, algún día, podrían ser llevadas a una arquitectura distribuída.

centralizada-vs-distribuida

Arquitecturas Centralizadas vs Arquitecturas Distribuídas

Como podemos observar, una arquitectura distribuída nos permite evitar puntos centralizados de fallos. Incluso, podríamos realizar la distribución a través de servicios DNS como Route53 de Amazon, que permiten directamente encargarse de resolver los nombres de dominio hacia las direcciones IP que se encuentren activas, realizando un balanceo de cargas en tiempo real.

Cabe destacar que lograr una arquitectura distribuída no es del todo sencillo, porque existen muchos detalles a tener en cuenta, pero es innegable que este tipo de arquitecturas resuelve varios de los problemas habituales de las aplicaciones web, como las actualizaciones de componentes sin caída de servicios y la rápida ampliación de capacidades de procesamiento.

Firewalls Dinámicos

Los cortafuegos (firewalls) más modernos soportan la interpretación del tráfico que pasa por ellos para detectar si nos encontramos en presencia de una ataque DoS o DDoS. Estas capacidades muchas veces son entregadas por los dispositivos UTM dentro de su capacidad de IDS/IPS.

En el caso de que estemos utilizando servidores y/o firewalls basados en GNU/Linux, podemos hacer uso de IPTables para limitar la cantidad máxima de conexiones concurrentes que pueden ser establecidas por una misma dirección IP, de la siguiente forma:

iptables -A INPUT -p TCP -m state --state NEW --dport 80 -m recent --set_
iptables -A INPUT -p TCP -m state --state NEW --dport 80 -m recent --update --seconds 60 --hitcount 5 -j DROP
iptables -A INPUT -p TCP -m state --state NEW --dport 80 -j ACCEPT

La 1ra línea deja un registro de la dirección IP origen por cada conexión nueva al puerto 80

La 2da línea verifica que no se hayan registrado más de 4 conexiones desde una misma dirección IP en los últimos 60 segundos. De ser así, empieza a descartar las conexiones de esa dirección.

La 3ra línea acepta la conexión (si es que la 2da línea no la rechazó)

Este es un ejemplo sencillo y práctico que, obviamente, puede ser mejorado agregando nuevas reglas y ajustando diferentes parámetros.

Apache ModEvasive

Este módulo de Apache, aunque funciona de forma completamente independiente a ModSecurity, es un excelente complemento para este, porque juntos proveen un nivel de seguridad muy interesante.

Es un módulo de Apache para prevenir ataques DoS y básicamente lo que hace es mantener una tabla dinámica con las URIs accedidas por las distintas IPs de los clientes, y permite ejecutar algunas acciones cuando una misma IP solicita un mismo recurso (una misma URI o elementos de un mismo sitio) más de n veces en m segundos.

La acción por default que ejecuta el mod_evasive es, una vez superado el máximo de requests por segundo permitidos, bloquear durante una cantidad de segundos al cliente (la IP) devolviendo un error 403 (Forbidden) a la petición HTTP. Pero lo interesante es que también permite ejecutar un comando de sistema al registrarse un intento de ataque, con lo cual se puede agregar una regla al iptables para bloquear la IP del cliente o cualquier otra acción que creamos conveniente, es totalmente personalizable.

A continuación podemos ver las instrucciones resumidas para su instalación y configuración:

1) Instalamos el paquete:

apt-get install libapache2-mod-evasive

2) Creamos el directorio en el que vamos a almacenar los logs y le permitimos a Apache escribir en él:

mkdir /var/log/mod_evasive
chown www-data:www-data /var/log/mod_evasive/

3) Creamos el archivo de configuración “/etc/apache2/mods-available/mod-evasive.conf” y lo editamos para que tenga el siguiente contenido:

<ifmodule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 10
DOSLogDir /var/log/mod_evasive
DOSEmailNotify EMAIL@DOMAIN.com
DOSWhitelist 127.0.0.1
</ifmodule>

Abajo podemos ver un pequeño resumen de las opciones que acabamos de configurar:

DOSHashTableSize: Establece el número de nodos a almacenar para cada proceso de peticiones de la tabla hash . Si aplicamos un número alto a este parámetro obtendremos un rendimiento mayor, ya que las iteraciones necesarias para obtener un registro de la tabla son menores. Por contra, y de forma evidente, aumenta el consumo de memoria necesario para el almacenamiento de una tabla mayor. Se hace necesario incrementar este parámetro si el servidor atiende un número abultado de peticiones, aunque puede no servir de nada si la memoria de la máquina es escasa.

DOSPageCount: Indica el valor del umbral para el número de peticiones de una misma página dentro del intervalo definido en DOSPageInterval. Cuando el valor del parámetro es excedido, la IP del cliente se añade a la lista de bloqueos.

DOSSiteCount: Cuenta cuántas peticiones de cualquier tipo puede hacer un cliente dentro del intervalo definido en DOSSiteInterval. Si se excede dicho valor, el cliente queda añadido a la lista de bloqueos.

DOSPageInterval: El intervalo, en segundos, para el umbral de petición de páginas.

DOSSiteInterval: El intervalo, en segundos, para el umbral de petición de objetos de cualquier tipo.

DOSBlockingPeriod: Establece el tiempo, en segundos, que un cliente queda bloqueado una vez que ha sido añadido a la lista de bloqueos.

DOSEmailNotify: Un e-mail será enviado a la dirección especificada cuando una dirección IP quede bloqueada.

DOSSystemCommand: El comando reflejado se ejecutará cuando una dirección IP quede bloqueada. Usaremos %s para especificar la dirección IP implicada.

DOSWhitelist: La dirección IP indicada como valor del parámetro no será tenida en cuenta por el módulo en ningún caso. Para cada dirección IP a excluir ha de añadirse una nueva línea con el parámetro.

4) Habilitamos el módulo y reiniciamos el servicio:

a2enmod mod-evasive
service apache2 restart  

Como podemos ver, es muy sencillo instalar y configurar este módulo para empezar a proteger nuestra infraestructura contra este tipo de ataques.

Resumen

A lo largo de esta serie de artículos hemos visto que tenemos varias tecnologías a nuestra disposición para aumentar la seguridad de nuestras aplicaciones web. Es muy importante que las implementemos pensando en las necesidades puntuales de nuestra organización y que, una vez implementadas, hagamos un monitoreo de los logs para detectar si están funcionando en la forma en la que lo esperamos y qué correcciones podemos hacer para optimizar cada medida de seguridad.

Escrito por: Fabian Martínez Portantier