Evitar ataques DOS con mod_evasive e iptables

Vamos a explicar como proteger un servidor web Apache contra ataques DOS y DDOS mediante el módulo mod_evasive y el firewall nativo de Linux IPTables.

El servidor corre Debian Lenny, y hago incapie en esto porque la configuración de Apache varía mucho según la distribución que estemos utilizando.

Ya tenemos el servidor instalado y configurado y nos interesa protegerlo, para ello instalamos el módulo de Apache mod_evasive:

apt-get install libapache2-mod-evasive

También es posible descargar y compilar, pero prefiero siempre en la medida de lo posible, usar paquetes proporcionados por la distribución.

En Debian Lenny, el archivo de configuración de Apache es /etc/apache2/apache2.conf en el podemos escribir la configuración del módulo, o mejor, comprobar que existe la línea

Include /etc/apache2/mods-enabled/*.conf

y añadir la configuración del módulo en un fichero nuevo dedicado, por mantener el orden, por ejemplo mod-evasive.conf La configuración que viene por defecto es la siguiente.

<IfModule evasive20_module>
  DOSHashTableSize 3097
  DOSPageCount 2
  DOSSiteCount 50
  DOSPageInterval 1
  DOSSiteInterval 1
  DOSBlockingPeriod 300
</IfModule>

Lo primero que debemos observar es el nombre del módulo, es variable según la distribución en la que nos encontremos o si lo hemos compilado nosotros eligiendo otro nombre.

La explicación de cada parámetro la transcribo de tail -f | systemadmin

  • DOSHashTableSize <valor> – Establece el número de nodos a almacenar para cada proceso de peticiones de la tabla hash (contenedor asociativo de recuperación de peticiones por medio de claves que agiliza las respuestas del servidor). 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 <valor> – Indica el valor del umbral para el número de peticiones de una misma página (o URI) 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 <valor> – 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 <valor> – El intervalo, en segundos, para el umbral de petición de páginas.
  • DOSSiteInterval <valor> – El intervalo, en segundos, para el umbral de petición de objetos de cualquier tipo.
  • DOSBlockingPeriod <valor> – Establece el tiempo, en segundos, que un cliente queda bloqueado una vez que ha sido añadido a la lista de bloqueos. Como ya se indicó unas líneas atrás, todo cliente bloqueado recibirá una respuesta del tipo 403 (Forbidden) a cualquier petición que realice durante este periodo.
  • DOSEmailNotify <e-mail> – Un e-mail será enviado a la dirección especificada cuando una dirección IP quede bloqueada. La configuración del proceso de envío se establece en el fichero mod_evasive.c de la forma /bin/mail -t %s, siendo %s el parámetro que queda configurado en este parámetro. Será necesario cambiar el proceso si usamos un método diferente de envío de e-mails y volver a compilar el módulo con apxs (por ejemplo, la opción t ha quedado obsoleta en las últimas versiones del comando).
  • DOSSystemCommand <comando> – El comando reflejado se ejecutará cuando una dirección IP quede bloqueada. Se hace muy útil en llamadas a herramientas de filtrado o firewalls. Usaremos %s para especificar la dirección IP implicada. Por ejemplo, podemos establecer su uso con iptables de la forma siguiente:
    DOSSystemCommand “/sbin/iptables –I INPUT –p tcp –-dport 80 –s %s –j DROP”
  • DOSLogDir <ruta> – Establece una ruta para el directorio temporal. Por defecto, dicha ruta queda establecida en /tmp, lo cual puede originar algunos agujeros de seguridad si el sistema resulta violado.
  • DOSWhitelist <IP> – 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. Por ejemplo, dejaremos fuera del chequeo del módulo a un posible bot que use los siguientes rangos de direcciones:
    DOSWhitelist 66.249.65.*
    DOSWhitelist 66.249.66.*
    

Para activar el módulo simplemente

# a2enmod mod-evasive

Como vemos tiene más opciones, la que ahora nos insteresa es la de DOSSystemCommand que es la que permite ejecutar acciones en el sistema.

IPTables es un programa para crear reglas de filtrado de tráfico de red, es un programa que debe ser ejecutado por un usuario con privilegios (root), pero siguiendo la Ley del permiso mínimo el servidor corre bajo un usuario no privilegiado, esta medida protege que ante un desbordamiento no quede una sesión privilegiada colgada.

El usuario que corre el servidor web no puede correr IPTables pero no está todo perdido, lo que tenemos que hacer es pasarle un mensaje a root con la IP que tiene que bloquear, y eso hemos visto ya como se puede hacer.

Primero añadimos la siguiente línea a nuestro fichero de configuración del módulo (en apache2.conf o en mod-evasive.conf)

DOSSystemCommand "/home/$USER/bin/checkIP %s"

En $USER/bin hemos escrito un script que actualizará un registro de IP que están haciendo más peticiones de la cuenta, el script tiene una pinte así

#!/bin/bash
# Este script llevara un fichero de log de los
# intentos de ataques DOS DDOS al servidor

DATE=$(date +%Y-%m-%d-%k-%M-%S);
LOGFILE="/home/$USER/bin/CheckIp.log";

echo $DATE $1 >> $LOGFILE;

Simplemente crea un log de IP’s con este formato:

2010-10-31-20-16-41 1.1.1.2
2010-10-31-20-16-41 86.217.15.159
2010-10-31-20-16-41 92.21.26.197

Ahora entra en juego root, que se encargará de supervisar este fichero y actuar si cambia, para ello nos apoyamos en incron, creamos una nueva regla de supervisión del sistema de fichero así

Abrimos el fichero
# incrontab -e
Editamos el fichero
/home/$USER/bin/CheckIP.log IN_MODIFY /root/bin/banIP

El script que hemos escrito banIP se ejecutará cada vez que se modifique el fichero CheckIP.log y pasara la IP a la lista de IPTables,

#!/bin/bash
LOGFILE="/home/$USER/bin/CheckIP.log";
IP=$(tail -n 1 $LOGFILE | cut -d" " -f 2);
/sbin/iptables -I INPUT -p tcp --dport 80 -s $IP -j DROP;

Para probar si está funcionando podemos ejecutar el script perl que proporciona el paquete mod_evasive, veremos algo como esto:

$ perl /usr/share/doc/libapache2-mod-evasive/examples/test.pl
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 403 Forbidden
Expiró el tiempo de conexión at test.pl line 12.

Con el reinicio del servidor se perderan las reglas si no se guardan.

Con esto hemos ganado unos cuantos puntos de seguridad, de por sí, mod_evasive evita exceso de peticiones, al combinarlo con IPTables liberamos a Apache de ese trabajo dejandolo en manos de un programa diseñado para eso.

This entry was posted in Apache, Linux and tagged , , , , , . Bookmark the permalink.

7 Responses to Evitar ataques DOS con mod_evasive e iptables

  1. Pingback: Tweets that mention nordri's Blog » Evitar ataques DOS con mod_evasive e iptables -- Topsy.com

  2. Fede, enhorabuena por el artículo, muy completo.

    Sólo una cosilla, ya que todo esto me queda un poco grande.

    Sobre las reglas de IPtables, no sería positivo la posibilidad de que dichas reglas expiraran?, eso nos permitiría tener una tabla de bloqueos menos cargada, es algo así como lo que hace fail2ban si no me equivoco no?.

    Sería genial encontrar también soluciones parecidas para Nginx, conoces/has probado alguna alternativa a mod_evasive 🙂

    Gracias por el artículo.

    Un saludo

  3. nordri says:

    @Miguel Ángel Martínez
    Gracias por el comentario Miguel Ángel,

    Comentarte que existe este módulo para NGINX http://wiki.nginx.org/NginxHttpLimitZoneModule que actúa parecido a Apache mod_evasive, limitando conexiones simultáneas.

    Respecto a la espiración de las reglas le he dado bastantes vueltas al asunto. Si una IP entra en la regla de iptable es porque realmente está haciendo algo malo, pero si toda la red de EDUROAM de la ETSII entra, se bloqueará la IP del router sin que se esté haciendo nada malo.

    Es más un estudio de estadística que otra cosa y hay que tomarlo con calma, o lanzarlo cuando realmente estén haciendo un ataque DOS porque veas que el servidor esté caido, o te avise monit.

    Un saludo.

  4. Jordi Prats says:

    Personalmente no me gustan estas soluciones porque, por decir un ejemplo, si entran un conjunto de alumnos saliendo por el típico proxy de la universidad seguro que los banearias.

  5. nordri says:

    @Jordi
    Si y no, no estoy seguro, el típico caso que comentas en el que un grupo de alumnos salen por el proxy de la universidad, se tendría que dar en un caso en el que todos los alumnos salgan al mismo tiempo a la misma página, es en lo que se basa la discriminación de mod_evasive.

    Estoy de acuerdo en que es muy “bruto” porque también se da el caso del usuario impaciente, que no para de darle a F5 y se queda bloquado.

    Más si lo que se trata es de bloquear un (D)DOS, pues si tienes más peticiones que ancho de banda, ya no hay iptables, ni mod_evasive, ni nada. Es lo que comentan en SbD, si hay un ataque, apaga y vamonos (o usa Akamai y su cache distribuida por todo el planeta)

    Creo que en el futuro con IPv6 no tendremos este problema, porque si puedes identificar a nivel de host y no de red, tenemos más capacidad para discriminar el tráfico legítimo del que no.

    Un saludo.

  6. Pingback: Evitar ataques DOS con mod_evasive e iptables | GubeX

  7. Pingback: Montar un Servidor Web | nordri's Blog

Comments are closed.