Implementación de rate limiting avanzado con iptables y nftables
Introducción
El rate limiting (limitación de velocidad o tasa) es una técnica fundamental en la administración de servidores para proteger la infraestructura contra ataques de denegación de servicio (DoS/DDoS), abuso de recursos, scraping automatizado y tráfico malicioso. Si bien existen soluciones a nivel de aplicación (nginx, Apache, Cloudflare), la implementación a nivel de firewall con iptables y nftables ofrece la capa más temprana y eficiente de defensa, operando directamente en el kernel de Linux. Este artículo explora estrategias avanzadas de rate limiting utilizando estas herramientas, desde conceptos fundamentales hasta configuraciones complejas para entornos de producción.
Conceptos Fundamentales: ¿Por qué a nivel de Firewall?
Implementar rate limiting en el firewall (capa de red/transporte) tiene ventajas críticas frente a soluciones en capas superiores:
- Eficiencia: El filtrado ocurre antes de que el tráfico llegue a la aplicación, ahorrando ciclos de CPU y memoria del servidor web o base de datos. El firewall, especialmente con nftables, opera en el espacio del kernel, minimizando la sobrecarga.
- Protección Temprana: Bloquea tráfico malicioso antes de que pueda saturar conexiones, ocupar sockets o consumir recursos del sistema.
- Universalidad: Protege cualquier servicio (HTTP, SSH, DNS, SMTP) sin necesidad de configurar cada aplicación individualmente.
- Bajo Nivel de Intervención: Permite implementar políticas de tráfico muy granulares basadas en direcciones IP, puertos, protocolos, interfaces e incluso estados de conexión.
Mecanismos de Rate Limiting en el Kernel de Linux
Tanto iptables como nftables utilizan módulos y mecanismos del kernel para lograr la limitación de tasa. Los más comunes son:
hashlimit(iptables) ymeter(nftables): Son los más potentes y flexibles. Permiten crear buckets de tokens por IP de origen (o por cualquier combinación de parámetros) y limitar la tasa de paquetes o bytes por segundo. Son ideales para escenarios avanzados donde se necesita un límite por cliente.limit(iptables) ylimit(nftables): Proporcionan un límite de tasa global (match) basado en un token bucket simple. Es útil para limitar logs o acciones, pero no para limitar por IP de origen. Es menos granular.connlimit(iptables) yct count(nftables): Permiten limitar el número de conexiones simultáneas desde una misma IP de origen. Esencial para mitigar ataques que abren muchas conexiones concurrentes.recent(iptables): Un módulo más antiguo que mantiene una lista de direcciones IP y permite hacer matching basado en el tiempo y la cantidad de paquetes vistos. Puede ser útil para escenarios simples, pero es menos eficiente y flexible quehashlimit/meter.
Tabla Comparativa de Mecanismos
| Característica | hashlimit (iptables) | meter (nftables) | limit (iptables/nftables) | connlimit (iptables) / ct count (nftables) |
|---|---|---|---|---|
| Granularidad | Por IP de origen (o hash personalizado) | Por IP de origen (o conjunto de claves) | Global (no por IP) | Por IP de origen |
| Métrica | Paquetes/segundo, Bytes/segundo | Paquetes/segundo, Bytes/segundo | Paquetes/segundo | Número de conexiones |
| Algoritmo | Token Bucket | Token Bucket | Token Bucket | Contador simple |
| Uso típico | Limitar peticiones HTTP por IP | Limitar peticiones HTTP por IP (moderno) | Limitar logs, acciones genéricas | Limitar conexiones SSH concurrentes |
| Rendimiento | Alto, diseñado para grandes volúmenes | Muy alto, más eficiente que hashlimit | Bajo, simple | Medio |
| Flexibilidad | Alta (múltiples opciones de hash) | Muy alta (expresiones complejas) | Muy baja | Baja |
Implementación Avanzada con iptables
Aunque iptables está siendo reemplazado por nftables, sigue siendo ampliamente utilizado. Las técnicas avanzadas se centran en el uso del módulo hashlimit.
Configuración Paso a Paso: Protección HTTP/HTTPS con hashlimit
Este ejemplo limita a 10 conexiones por segundo desde una misma IP hacia los puertos 80 y 443, con un burst inicial de 20 conexiones.
1. Crear las reglas en la cadena INPUT:
# Limitar tráfico HTTP (puerto 80)
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m hashlimit \
--hashlimit-name http_rate_limit \
--hashlimit-mode srcip \
--hashlimit-upto 10/sec \
--hashlimit-burst 20 \
-j ACCEPT
# Limitar tráfico HTTPS (puerto 443)
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m hashlimit \
--hashlimit-name https_rate_limit \
--hashlimit-mode srcip \
--hashlimit-upto 10/sec \
--hashlimit-burst 20 \
-j ACCEPT
Explicación detallada:
-m state --state NEW: Aplica la regla solo a paquetes que inician una nueva conexión. Es crucial para no limitar paquetes de conexiones ya establecidas, lo que rompería el tráfico legítimo.-m hashlimit: Carga el módulohashlimit.--hashlimit-name http_rate_limit: Nombre único para el bucket de tokens. Cada nombre crea un bucket separado.--hashlimit-mode srcip: El hash se calcula solo basado en la dirección IP de origen. También se puede usarsrcip,dstip,srcip,dstport, etc.--hashlimit-upto 10/sec: Tasa máxima sostenida de 10 paquetes por segundo.--hashlimit-burst 20: Tamaño del burst inicial. Permite hasta 20 paquetes en una ráfaga antes de que se aplique el límite de 10/seg.-j ACCEPT: Si el paquete está dentro del límite, se acepta.
2. Regla de Drop para tráfico excedido:
Las reglas anteriores solo aceptan tráfico que cumple con el límite. El tráfico excedido caerá a la siguiente regla. Es vital tener una regla de drop al final de la cadena INPUT para los paquetes que no fueron aceptados:
# Después de todas las reglas de rate limiting, añadir una regla de drop general
iptables -A INPUT -m state --state NEW -j DROP
Nota Importante: La posición de las reglas es crítica. Las reglas de rate limiting deben colocarse antes de la regla de drop general. Además, asegúrate de tener reglas de
ACCEPTpara tráfico establecido y relacionado al principio de la cadenaINPUT:iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Escenario Avanzado: Límites por IP Diferentes para HTTP y SSH
Podemos tener buckets separados para diferentes servicios usando diferentes --hashlimit-name.
# SSH: 3 conexiones nuevas por minuto, burst de 5
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m hashlimit \
--hashlimit-name ssh_rate_limit \
--hashlimit-mode srcip \
--hashlimit-upto 3/minute \
--hashlimit-burst 5 \
-j ACCEPT
# HTTP API: 100 peticiones por segundo, burst de 200
iptables -A INPUT -p tcp --dport 8080 -m state --state NEW -m hashlimit \
--hashlimit-name api_rate_limit \
--hashlimit-mode srcip \
--hashlimit-upto 100/sec \
--hashlimit-burst 200 \
-j ACCEPT
Implementación Moderna y Eficiente con nftables
nftables es el sucesor de iptables, ofreciendo un rendimiento superior, una sintaxis más limpia y una gestión de estado más eficiente. El equivalente a hashlimit es la declaración meter.
Sintaxis Básica de un meter en nftables
Un meter es un diccionario dinámico que cuenta paquetes. Se define como parte de una regla.
nft add rule inet filter input tcp dport {http, https} \
ct state new \
meter http-meter { ip saddr limit rate 10/second burst 20 packets } \
accept
Explicación:
inet filter input: La tabla y cadena (usando la familiainetpara IPv4 e IPv6).tcp dport {http, https}: Aplica a los puertos 80 y 443.ct state new: Solo nuevas conexiones.meter http-meter { ... }: Define unmeterllamadohttp-meter.ip saddr: La clave delmeteres la dirección IP de origen.limit rate 10/second burst 20 packets: Límite de 10 paquetes por segundo con un burst de 20.accept: Si el paquete está dentro del límite, se acepta.
Configuración Paso a Paso: Protección de API REST con nftables
Este ejemplo protege una API REST en el puerto 3000, limitando a 50 peticiones por segundo por IP, con un burst de 100.
1. Crear la tabla y la cadena base (si no existen):
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
2. Añadir reglas de estado establecido:
nft add rule inet filter input ct state established,related accept
3. Añadir la regla de rate limiting:
nft add rule inet filter input tcp dport 3000 \
ct state new \
meter api-rate-limit { ip saddr limit rate 50/second burst 100 packets } \
accept
4. Verificar la configuración:
nft list ruleset
Escenario Avanzado: Límite con Logging y Drop Explícito
Podemos añadir una regla que registre (log) los paquetes que exceden el límite antes de hacer drop.
# Regla que acepta si está dentro del límite
nft add rule inet filter input tcp dport 3000 \
ct state new \
meter api-rate-limit { ip saddr limit rate 50/second burst 100 packets } \
accept
# Regla que registra y dropea el exceso
nft add rule inet filter input tcp dport 3000 \
ct state new \
log prefix "RATE_LIMIT_EXCEEDED: " \
drop
Nota sobre el rendimiento: El
meteren nftables es extremadamente eficiente. Sin embargo, para escenarios con millones de IPs únicas, el tamaño de la tabla hash delmeterpuede crecer. Se puede limitar el tamaño del meter usandosize:meter api-rate-limit { ip saddr limit rate 50/second burst 100 packets size 100000 }Esto limita el meter a 100,000 entradas. Cuando se excede, las entradas más antiguas se eliminan.
Estrategias Avanzadas de Rate Limiting
1. Rate Limiting Basado en Bytes (No Solo Paquetes)
Para proteger contra ataques de amplificación (como ataques NTP o DNS), es más efectivo limitar por bytes en lugar de paquetes.
nftables:
meter dns-amplification { ip saddr limit rate over 10 mbytes/second }
iptables:
iptables -A INPUT -p udp --dport 53 -m hashlimit \
--hashlimit-name dns_amplification \
--hashlimit-mode srcip \
--hashlimit-upto 10mb/sec \
--hashlimit-burst 20mb \
-j ACCEPT
2. Rate Limiting por Conexiones Simultáneas (SYN Flood Mitigation)
Limitar el número de conexiones simultáneas desde una IP ayuda a mitigar ataques SYN flood.
nftables (usando ct count):
# Limitar a 10 conexiones simultáneas por IP al puerto 80
nft add rule inet filter input tcp dport 80 \
ct state new \
meter syn-flood { ip saddr ct count over 10 } \
drop
iptables (usando connlimit):
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 10 -j DROP
3. Rate Limiting Geográfico o por Listas
Combinar rate limiting con sets o listas de IPs permite aplicar límites diferentes a rangos de IPs específicos (ej. permitir más tráfico desde IPs de confianza).
nftables:
# Crear un conjunto de IPs de confianza
nft add set inet filter trusted_ips { type ipv4_addr \; }
# Añadir IPs al conjunto (ejemplo)
nft add element inet filter trusted_ips { 192.168.1.0/24, 10.0.0.5 }
# Regla: Si la IP está en trusted_ips, límite más alto
nft add rule inet filter input tcp dport 3000 \
ip saddr @trusted_ips \
ct state new \
meter api-trusted-rate { ip saddr limit rate 500/second burst 1000 packets } \
accept
# Regla para el resto de IPs, límite más bajo
nft add rule inet filter input tcp dport 3000 \
ct state new \
meter api-public-rate { ip saddr limit rate 50/second burst 100 packets } \
accept
4. Rate Limiting Dinámico con nft y Scripts
Puedes usar scripts para actualizar dinámicamente los límites o los sets basados en condiciones del sistema (ej. carga de CPU, número de conexiones).
#!/bin/bash
# Script simple para aumentar el límite si la carga de CPU es baja
CPU_LOAD=$(uptime | awk -F'load average:' '{ print $2 }' | cut -d, -f1 | tr -d ' ')
if (( $(echo "$CPU_LOAD < 1.0" | bc -l) )); then
# Aumentar burst
nft add rule inet filter input tcp dport 3000 \
ct state new \
meter api-rate-limit { ip saddr limit rate 50/second burst 200 packets } \
accept
else
# Reducir burst
nft add rule inet filter input tcp dport 3000 \
ct state new \
meter api-rate-limit { ip saddr limit rate 50/second burst 50 packets } \
accept
fi
Monitoreo y Depuración de Reglas de Rate Limiting
Ver Estadísticas de hashlimit (iptables)
# Mostrar estadísticas del módulo hashlimit
cat /proc/net/ipt_hashlimit/http_rate_limit
# Formato de salida:
# entries: Número de entradas en la tabla hash
# packets: Paquetes totales procesados
# bytes: Bytes totales procesados
# rate: Tasa actual
Ver Estadísticas de meter (nftables)
# Listar las reglas con contadores
nft list ruleset -a
# Ver información específica del meter (si el kernel lo soporta)
# nft no tiene una interfaz directa para ver el contenido del meter, pero se puede monitorear a través de contadores en las reglas.
Monitoreo en Tiempo Real con tcpdump y iptables -L -v
# Ver reglas con contadores de paquetes y bytes
iptables -L -v -n --line-numbers
# Para nftables
nft list ruleset
# Monitorear paquetes que son dropeados
tcpdump -i eth0 tcp port 80 and 'tcp[tcpflags] & (tcp-syn) != 0' and 'src net 0.0.0.0/0' and 'tcp[13] & 2 != 0'
Consideraciones de Rendimiento y Seguridad
- Tamaño de la Tabla Hash: Tanto
hashlimitcomometer
