Slowloris : comment nftables et conntrack tuent l'attaque lente
L'attaque Slowloris reste en 2026 l'une des menaces applicatives les plus insidieuses : un seul poste d'attaque monopolise les slots TCP d'un serveur web en maintenant des centaines de connexions semi-ouvertes. La clé pour contrer ce scénario sans bloquer les clients légitimes réside dans nftables conntrack Slowloris, un duo kernel-level qui observe l'état de chaque connexion et applique des limites granulaires par flux. Ce guide détaille comment nftables, via le module conntrack, neutralise Slowloris en 2026 avec une configuration éprouvée et compatible avec XDP.
Comprendre le mode opératoire de Slowloris et pourquoi conntrack est indispensable
Slowloris ne sature pas la bande passante : il envoie des en-têtes HTTP incomplets, lentement, pour maintenir chaque connexion TCP ouverte le plus longtemps possible. Un serveur web configuré pour 512 workers accepte 512 connexions simultanées ; dès que ce seuil est atteint, les clients légitimes sont refusés. Contrairement aux attaques volumétriques (SYN flood, UDP amplification), Slowloris exploite le comportement stateful du serveur, ce qui rend inutiles les approches stateless classiques.
Le module conntrack de nftables (Connection Tracking) enregistre chaque tuple (IP source, port source, IP destination, port destination, protocole) dans une table d'état kernel. En marquant chaque paquet avec son état — NEW, ESTABLISHED, RELATED, INVALID — conntrack permet de :
- Limiter le nombre de nouvelles connexions par seconde et par IP source (
ct state new). - Isoler les connexions établies (
ct state established,related) et les autoriser sans surcoût. - Compter les connexions simultanées par IP source avec un
meteret rejeter au-delà d'un seuil. - Surveiller les états TCP anormaux (
INVALID) et les drainer avant qu'ils n'atteignent l'application.
Cette approche stateful complète le filtrage stateless XDP : XDP traite les paquets uniques (rate-limit global par pps, filtrage port/protocole) tandis que nftables+conntrack raisonne par flux. PAKKT.io orchestre les deux couches dans une table inet pakkt isolée, sans conflit avec Docker, fail2ban ou iptables-persistent.
Configuration nftables anti-Slowloris : règles conntrack et meter en action
Voici une politique éprouvée pour un serveur web exposé sur TCP/80 et TCP/443. Chaque règle s'appuie sur ct state pour observer l'état de la connexion et sur un meter pour compter en temps réel.
Étape 1 : créer la table et les chaînes de base
nft add table inet pakkt
nft add chain inet pakkt input { type filter hook input priority filter \; policy accept \; }
nft add chain inet pakkt forward { type filter hook forward priority filter \; policy accept \; }
La table inet pakkt traite simultanément IPv4 et IPv6. La priorité filter (0) place ces règles après le conntrack mais avant la plupart des règles applicatives.
Étape 2 : accepter le trafic établi et related sans limite
nft add rule inet pakkt input ct state established,related accept
Cette règle autorise immédiatement toute réponse d'un flux déjà ouvert. Les connexions légitimes (navigateurs, API) passent sans déclencher les compteurs de nouvelles connexions.
Étape 3 : limiter les nouvelles connexions HTTP/HTTPS par IP source
nft add rule inet pakkt input tcp dport { 80, 443 } ct state new \
meter slowloris_limit { ip saddr limit rate over 20/second burst 40 packets } \
counter drop
Le meter slowloris_limit maintient un compteur par IP source. Si une même IP tente d'ouvrir plus de 20 nouvelles connexions TCP par seconde sur les ports 80 ou 443 (avec un burst autorisé de 40), les paquets excédentaires sont droppés avant d'atteindre le serveur web. Un client légitime, même sur une page riche en ressources, ouvre rarement plus de 10 à 15 connexions simultanées ; un attaquant Slowloris en tente plusieurs centaines.
Étape 4 : limiter les connexions simultanées par IP source
nft add rule inet pakkt input tcp dport { 80, 443 } ct state new \
add @concurrent_conns { ip saddr ct count over 50 } \
counter reject with tcp reset
Le set dynamique @concurrent_conns compte les connexions actives (ct count) par IP. Au-delà de 50 connexions simultanées, nftables envoie un TCP RST pour libérer proprement le slot, évitant que l'attaquant ne monopolise les ressources kernel. Pour un serveur web classique, 50 connexions simultanées par IP client suffisent largement ; ajuste ce seuil selon ton architecture (reverse proxy, CDN en amont).
Étape 5 : rejeter les états TCP invalides
nft add rule inet pakkt input ct state invalid counter drop
Conntrack marque invalid les paquets qui ne correspondent à aucun flux connu (numéros de séquence aberrants, flags TCP incohérents). Ces paquets sont typiques d'un scan ou d'une tentative d'injection ; les drainer en amont protège les applications.
Étape 6 : accepter les nouvelles connexions restantes (trafic légitime)
nft add rule inet pakkt input tcp dport { 80, 443 } ct state new limit rate 1000/second accept
Cette règle de fallback accepte jusqu'à 1000 nouvelles connexions par seconde globales. Ce plafond global protège contre une attaque distribuée (botnet) où chaque IP respecte la limite individuelle mais le volume agrégé submerge le serveur.
Intégration avec XDP : complémentarité stateless + stateful sur la même box
Le PAKKT Engine (programme XDP unique par interface) traite les paquets en sub-microseconde, avant même l'allocation de sk_buff kernel. XDP est idéal pour :
- Rate-limit global par pps : si l'interface reçoit plus de 5 millions de pps, XDP drop l'excédent immédiatement, protégeant le stack IP entier.
- Filtrage par port/protocole : bloquer tous les paquets UDP/19132 (Minecraft Bedrock) ou TCP/3389 (RDP) si ces services ne sont pas exposés.
- Blacklist/Whitelist IP : une BPF map contenant jusqu'à 256 entrées, synchronisée depuis le panel PAKKT. Les IP blacklistées sont droppées en 200 ns par paquet.
nftables+conntrack intervient après XDP, pour les paquets qui ont passé le premier filtre. Ainsi :
- XDP élimine les attaques volumétriques brutes (UDP flood, SYN flood massif).
- nftables conntrack inspecte les flux TCP survivants et applique des limites par connexion, neutralisant Slowloris et les scans applicatifs.
Exemple de flux complet pour un paquet TCP SYN destination 443 :
1. XDP : vérifier IP source dans BPF map blacklist → passé
2. XDP : vérifier rate-limit global 5M pps → passé
3. XDP : action XDP_PASS → paquet remis au stack kernel
4. nftables : ct state new → meter slowloris_limit → compteur IP source 18/sec → accepté
5. nftables : ct count 42 connexions actives → accepté
6. nftables : ct state new limit 1000/sec global → accepté
7. Application (nginx, Apache) : accept() réussit
Cette architecture garantit une défense en profondeur sans redondance coûteuse : chaque couche traite ce pour quoi elle est optimisée. PAKKT centralise la configuration XDP et nftables dans un panel unifié, avec audit log, métriques par règle (TimescaleDB) et synchronisation automatique des listes IP.
Surveillance et tuning : métriques conntrack et optimisation kernel
Le système conntrack expose ses compteurs via /proc/sys/net/netfilter/. Trois paramètres critiques pour résister à Slowloris :
Augmenter la table conntrack (nf_conntrack_max)
sysctl -w net.netfilter.nf_conntrack_max=262144
echo "net.netfilter.nf_conntrack_max = 262144" >> /etc/sysctl.conf
Par défaut, la table conntrack accepte 65536 connexions simultanées. Un serveur web sous attaque Slowloris peut voir 100 000 connexions semi-ouvertes ; augmenter nf_conntrack_max évite le rejet prématuré de connexions légitimes lorsque la table déborde.
Réduire les timeouts TCP (nf_conntrack_tcp_timeout_*)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=600
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=30
Une connexion Slowloris reste dans l'état ESTABLISHED pendant des heures si le serveur ne détecte pas l'inactivité applicative. Réduire nf_conntrack_tcp_timeout_established de 5 jours (par défaut) à 10 minutes libère les slots plus vite. Attention : des clients légitimes sur connexions longues (WebSocket, SSE) peuvent être coupés ; teste en environnement de staging.
Activer le logging des drops conntrack pour audit
nft add rule inet pakkt input tcp dport { 80, 443 } ct state new \
meter slowloris_limit { ip saddr limit rate over 20/second burst 40 packets } \
log prefix "[PAKKT-SLOWLORIS] " counter drop
Le préfixe [PAKKT-SLOWLORIS] apparaît dans dmesg ou /var/log/kern.log. Corrèle ces logs avec les métriques GeoIP du panel PAKKT (top IPs sources, top pays) pour identifier les sources d'attaque et alimenter la blacklist automatiquement.
Vérifier l'usage de la table conntrack en temps réel
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
Si nf_conntrack_count approche nf_conntrack_max, le kernel commence à rejeter de nouvelles connexions (nf_conntrack: table full dans dmesg). Monte nf_conntrack_max et ajuste les timeouts en priorité. Le dashboard PAKKT affiche ces métriques kernel en temps réel (graphiques sur 24h) pour anticiper les saturations.
Cas d'usage réels : serveurs web, API REST, WebSocket et game servers
Serveur web Apache ou nginx exposé publiquement
Configuration type : 80/443 ouverts, 1000 req/s en pointe légitime, attaques Slowloris récurrentes la nuit. Applique les règles ci-dessus avec :
meter slowloris_limit: 20 nouvelles connexions/sec/IP, burst 40.ct count: 50 connexions simultanées/IP.- Timeout
established: 600 secondes (10 min).
Résultat observé : l'attaque Slowloris (1 IP, 500 connexions lentes) est bloquée dès la 51ᵉ connexion simultanée. Les clients légitimes (10 à 15 connexions par session de navigation) ne déclenchent jamais le meter.
API REST avec authentification JWT
Les API REST acceptent généralement 1 connexion par requête (HTTP/1.1 keepalive ou HTTP/2 multiplexing). La limite de 50 connexions simultanées/IP peut être trop élevée. Ajuste :
nft add rule inet pakkt input tcp dport 8080 ct state new \
add @concurrent_conns { ip saddr ct count over 10 } \
counter reject with tcp reset
Un client API légitime maintient rarement plus de 5 connexions actives. Cette règle protège contre un script malveillant qui ouvre 100 connexions pour épuiser les workers backend.
WebSocket (Minecraft Java, chat en temps réel)
Les connexions WebSocket restent ouvertes pendant des heures. Slowloris est moins efficace (le handshake WebSocket est complet), mais un attaquant peut ouvrir 500 WebSockets et ne jamais envoyer de message. Configuration adaptée :
meter slowloris_limit: 10 nouvelles connexions/sec/IP, burst 20 (un joueur Minecraft ouvre 1 WebSocket, pas 50).ct count: 5 connexions simultanées/IP (un joueur = 1 connexion).- Timeout
established: conserver 7200 secondes (2h) pour les sessions longues légitimes.
Minecraft Bedrock (UDP/19132) est géré par XDP : rate-limit global par pps et filtrage par taille de paquet (paquets < 32 bytes droppés). Aucun besoin de conntrack pour UDP stateless. PAKKT s'intègre à Pterodactyl pour synchroniser automatiquement les règles XDP et nftables selon le type de serveur de jeu (Java, Bedrock, FiveM, etc.).
Comparaison avec les approches alternatives et limites de conntrack
| Méthode | Efficacité Slowloris | Impact performance | Complémentarité PAKKT |
| nftables conntrack + meter | Excellente (limite par flux) | Faible (~5 µs par paquet) | Couche stateful après XDP stateless |
| mod_reqtimeout (Apache) | Bonne (timeout applicatif) | Moyen (workers occupés) | Complémentaire : applique en amont, mod_reqtimeout en dernier recours |
| nginx limit_conn | Bonne (limite applicative) | Moyen (parsing HTTP requis) | Complémentaire : nftables filtre avant nginx |
| fail2ban + iptables | Réactive (détection post-mortem) | Élevé (regex sur logs, latence ban) | Redondant : nftables meter est temps réel, zéro parsing log |
| Scrubbing cloud (Cloudflare, OVH VAC) | Excellente (challenge JavaScript) | Nul (hors serveur) | Complémentaire : scrubbing en amont, PAKKT sur le serveur final |
Limites de conntrack : la table d'état consomme de la RAM (~300 bytes par connexion). Sur un serveur avec 1 million de connexions simultanées, cela représente ~300 MB de RAM kernel. Pour les infrastructures massivement parallèles (CDN interne, load balancer), privilégie un scrubbing en amont et conserve nftables conntrack comme dernière couche sur les backends. PAKKT est conçu pour des serveurs unitaires (game servers, API monolithiques, VPS) où la table conntrack tient aisément en mémoire.
Autre limite : conntrack ne décode pas HTTP. Il voit un flux TCP mais ne distingue pas une requête HTTP lente légitime (upload de fichier 10 MB) d'une requête Slowloris (en-tête incomplet). C'est pourquoi les règles se basent sur le volume de nouvelles connexions et le nombre de connexions simultanées, pas sur le contenu applicatif. Pour un filtrage L7 (User-Agent, URL, body), utilise un reverse proxy ou un WAF en amont — PAKKT reste sur L2/L3/L4.
Exemple de configuration complète prête à l'emploi
Voici un jeu de règles nftables anti-Slowloris pour un serveur web classique (80/443), compatible avec PAKKT.io. Sauvegarde dans /etc/nftables.conf et active avec systemctl enable nftables && systemctl start nftables.
#!/usr/sbin/nft -f
# Table PAKKT isolée (inet = IPv4 + IPv6)
table inet pakkt {
# Set dynamique pour compter les connexions simultanées par IP
set concurrent_conns {
type ipv4_addr
flags dynamic
}
# Chaîne input : hook netfilter priorité filter
chain input {
type filter hook input priority filter; policy accept;
# Accepter immédiatement le trafic établi et related
ct state established,related accept
# Accepter loopback sans limite
iif lo accept
# Rejeter les états invalides
ct state invalid counter drop
# Rate-limit nouvelles connexions HTTP/HTTPS par IP source
tcp dport { 80, 443 } ct state new \
meter slowloris_limit { ip saddr limit rate over 20/second burst 40 packets } \
log prefix "[PAKKT-SLOWLORIS] " counter drop
# Limiter les connexions simultanées par IP source
tcp dport { 80, 443 } ct state new \
add @concurrent_conns { ip saddr ct count over 50 } \
counter reject with tcp reset
# Limite globale de nouvelles connexions (protection DDoS distribué)
tcp dport { 80, 443 } ct state new limit rate 1000/second accept
# Accepter les nouvelles connexions restantes
tcp dport { 80, 443 } ct state new accept
}
chain forward {
type filter hook forward priority filter; policy accept;
}
}
Pour vérifier que les règles sont actives :
nft list ruleset | grep pakkt
nft list meter inet pakkt slowloris_limit
Le meter slowloris_limit affiche les IP sources qui ont déclenché la limite, avec leur compteur actuel. Corrèle ces IP avec le dashboard GeoIP de PAKKT pour identifier les zones géographiques sources et ajuster la blacklist si nécessaire.
Pour purger manuellement une IP du meter (test ou faux positif) :
nft delete element inet pakkt slowloris_limit { 203.0.113.42 }
Recommandations de déploiement et supervision continue
Une fois les règles nftables en place, la supervision continue est essentielle. Points de contrôle recommandés :
- Dashboard PAKKT : métriques temps réel par port, top IPs sources, top pays, audit log des modifications de règles. Le panel affiche le taux de drop nftables par règle (compteur
counter drop) et alerte si une IP légitime est bloquée à tort. - Logs kernel :
journalctl -k -f | grep PAKKTaffiche en direct les paquets loggés par le préfixe[PAKKT-SLOWLORIS]. Corrèle avec les logs applicatifs (nginx access.log) pour distinguer les vrais clients des attaquants. - Métriques Prometheus : exporte
nf_conntrack_count,nf_conntrack_max, et le compteur de drops nftables vianode_exporter. Alerte sinf_conntrack_countdépasse 80 % denf_conntrack_max. - Tests de charge : simule une attaque Slowloris avec
slowhttptest(GitHub shekyan/slowhttptest) pour valider que les règles bloquent sans faux positif. Exemple :slowhttptest -c 1000 -H -g -o slowloris_test -i 10 -r 200 -t GET -u https://ton-serveur.example.com/.
En environnement de production, active d'abord les règles en mode log sans drop pendant 48h, analyse les IPs loggées, puis bascule en mode drop une fois les seuils validés. PAKKT permet de synchroniser cette bascule sur tous les agents en un clic depuis le panel.
Pour un serveur multi-tenant (hébergeur de game servers, SaaS), isole chaque tenant dans une chaîne nftables dédiée avec son propre meter et ct count. Exemple :
nft add chain inet pakkt tenant_minecraft_1
nft add rule inet pakkt input tcp dport 25565 jump tenant_minecraft_1
nft add rule inet pakkt tenant_minecraft_1 ct state new \
meter mc1_limit { ip saddr limit rate over 10/second burst 20 packets } \
counter drop
Cette architecture évite qu'un tenant sous attaque n'épuise la table conntrack globale et n'impacte les autres tenants. PAKKT facture 3€/agent/mois, permettant de déployer un agent par tenant si l'isolation physique (VM dédiée par tenant) est requise.
En résumé, nftables conntrack Slowloris repose sur trois piliers : observation de l'état par flux (ct state), limitation granulaire par IP (meter), et comptage des connexions simultanées (ct count). Couplé à XDP pour la première ligne de défense stateless, ce stack kernel-level offre une protection sub-milliseconde sans coût applicatif, directement sur le serveur cible.
Conclusion
L'attaque Slowloris exploite la gestion stateful des connexions TCP, mais le duo nftables conntrack retourne cette logique contre l'attaquant : en traçant chaque flux et en limitant les nouvelles connexions par IP source, le kernel Linux neutralise l'attaque avant qu'elle n'atteigne l'application. Combiné à XDP pour le filtrage stateless, ce stack kernel-level garantit une défense en profondeur sans latence mesurable. La configuration présentée ici est éprouvée en production, évolutive et compatible avec les architectures modernes (conteneurs, multi-tenant, intégrations CI/CD via API).
FAQ
Quelle différence entre le rate-limit XDP (max_pps) et le meter nftables pour contrer Slowloris ?
XDP rate-limite le volume total de paquets par seconde sur l'interface (stateless, traite chaque paquet isolément). Le meter nftables rate-limite les nouvelles connexions TCP par IP source (stateful, observe le flux). Pour Slowloris, le meter est indispensable car l'attaque envoie peu de paquets mais ouvre beaucoup de connexions. XDP protège contre les floods volumétriques en amont, nftables affine par flux. PAKKT orchestre les deux couches dans une table inet pakkt unifiée.
Puis-je utiliser ces règles nftables si j'ai déjà fail2ban ou Docker actifs sur le serveur ?
Oui, la table inet pakkt est isolée et ne modifie pas les chaînes INPUT, FORWARD ou DOCKER existantes. nftables gère plusieurs tables simultanément sans conflit. fail2ban peut continuer à bannir via iptables-legacy ou nftables dans sa propre table. Docker crée une table nat pour le NAT conteneur. PAKKT se branche en priorité filter (0), après conntrack, et traite uniquement les paquets entrants sur les ports configurés. Teste en environnement de staging pour valider la coexistence.
Comment ajuster les seuils (20 connexions/sec, 50 connexions simultanées) selon mon trafic légitime ?
Active d'abord les règles en mode log sans drop pendant 48h : remplace counter drop par log prefix "[TEST] " counter. Analyse les logs (journalctl -k | grep TEST) pour identifier les IPs légitimes qui dépassent le seuil. Si un CDN ou un reverse proxy agrège le trafic derrière une IP unique, whitelist cette IP (ip saddr 203.0.113.10 accept avant les règles de meter) ou monte le seuil (ex. 100 connexions/sec). Pour un serveur API REST, descends à 10 connexions simultanées/IP. Pour un WebSocket (Minecraft), descends à 5. Le dashboard PAKKT affiche les compteurs par règle pour faciliter ce tuning.
Déployez PAKKT en 30 secondes
Protection kernel double couche XDP + nftables, pilotable depuis un panel centralisé. Essai gratuit 7 jours.