Protéger un site Nginx contre une attaque applicative (L7)

Publié le 21/08/2026 Mis à jour le 21/08/2026 4 vues
Sécurité VPS Linux Nginx DDoS

Toutes les attaques ne se ressemblent pas. Une attaque volumétrique cherche à saturer le lien réseau : c’est un embouteillage sur l’autoroute, et c’est la protection By-Hoster qui s’en charge en amont, sans que vous ayez rien à faire.

Une attaque applicative, dite de couche 7, est différente. Le trafic reste modeste, mais chaque requête est coûteuse : une recherche, une page de connexion, un panier. Pour le réseau, ce sont des visiteurs normaux. Ce n’est qu’au niveau de votre serveur web que la nature du trafic devient visible, et c’est donc là qu’il faut agir.

Comment savoir ce qui frappe réellement mon serveur ?

Ne changez rien tant que vous ne savez pas ce qui arrive. Un réglage posé au hasard bloque souvent vos vrais visiteurs sans gêner l’attaquant.

Les adresses IP les plus actives :

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Les URL les plus demandées :

awk -F'"' '{print $2}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Le trafic sur la dernière minute, pour juger de l’intensité :

tail -n 100000 /var/log/nginx/access.log | awk '{print $4}' | uniq -c | tail -20

Vous cherchez un motif : une poignée d’adresses très bavardes, une URL unique martelée, un agent utilisateur identique partout. C’est ce motif qui dictera la règle, pas l’inverse.

Vérifiez aussi ce qui sature réellement :

uptime
systemctl status php8.3-fpm --no-pager

Souvent, ce n’est pas Nginx qui plie mais PHP ou la base de données derrière.

Comment limiter le débit de requêtes par adresse dans Nginx ?

Nginx sait compter les requêtes par adresse et ralentir celles qui dépassent. La déclaration des zones se fait dans le bloc http (fichier /etc/nginx/nginx.conf) :

http {
    limit_req_zone  $binary_remote_addr zone=req_par_ip:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn_par_ip:10m;
}

Puis l’application dans le bloc du site :

server {
    limit_req  zone=req_par_ip burst=20 nodelay;
    limit_conn conn_par_ip 20;
}

Ce que cela veut dire, concrètement :

Réglage Effet
rate=10r/s 10 requêtes par seconde et par adresse en régime normal
burst=20 tolère une pointe de 20 requêtes au-delà du rythme
nodelay sert la pointe immédiatement au lieu de l’étaler
limit_conn 20 20 connexions simultanées au maximum par adresse

Une zone de 10m mémorise environ 160 000 adresses, largement assez.

burst sans nodelay met les requêtes en file d’attente : le site devient lent au lieu de refuser. Avec nodelay, un visiteur normal qui charge une page et ses vingt ressources passe sans ralentissement, tandis qu’un robot qui insiste reçoit une erreur 503.

Protégez plus sévèrement les URL réellement coûteuses plutôt que tout le site :

location = /wp-login.php {
    limit_req zone=req_par_ip burst=3 nodelay;
}

Comment tester la configuration Nginx avant de l’appliquer ?

Avec nginx -t, qui valide la syntaxe sans rien appliquer, puis un rechargement à chaud plutôt qu’un redémarrage.

nginx -t

Cette commande valide la syntaxe sans rien interrompre. Elle doit répondre syntax is ok puis test is successful. Ensuite seulement :

systemctl reload nginx

reload recharge la configuration sans couper les connexions en cours, contrairement à restart. En pleine attaque, la différence compte.

Surveillez ce qui est refusé :

grep "limiting requests" /var/log/nginx/error.log | tail -20

Si vous voyez apparaître vos propres adresses ou celles de vos clients, la limite est trop basse. Remontez-la.

Comment servir moins souvent la même page ?

Le meilleur moyen d’encaisser une attaque est souvent de ne pas recalculer la page à chaque requête. Une page mise en cache 60 secondes coûte quasiment rien, quel que soit le nombre de demandes.

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=site:50m inactive=10m;
}
location / {
    proxy_cache site;
    proxy_cache_valid 200 60s;
    proxy_cache_use_stale error timeout updating;
}

proxy_cache_use_stale est la ligne qui sauve : si le backend ne répond plus, Nginx continue de servir la dernière version connue plutôt qu’une erreur.

Sur WordPress, PrestaShop ou Laravel, un module de cache applicatif produit le même effet avec moins de risques d’effets de bord.

Comment bannir les adresses récidivistes avec fail2ban ?

Limiter ralentit ; bannir arrête. fail2ban lit les journaux et ajoute une règle de pare-feu contre les adresses qui déclenchent trop souvent la limite.

apt install fail2ban

Dans /etc/fail2ban/jail.local :

[nginx-limit-req]
enabled  = true
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime  = 3600
systemctl restart fail2ban
fail2ban-client status nginx-limit-req

Lue à voix haute, la règle donne : une adresse qui déclenche 10 fois la limitation en 60 secondes est bloquée pendant une heure.

Quels réglages faut-il éviter face à une attaque applicative ?

Ces réglages circulent beaucoup et font plus de mal que de bien.

À éviter Pourquoi
Bloquer curl et wget sur l’agent utilisateur Un attaquant change d’agent en une ligne. Vous, vous cassez votre supervision, vos webhooks de paiement et vos scripts de sauvegarde.
client_max_body_size 1k Toute mise en ligne d’image, tout formulaire un peu long, toute mise à jour de CMS échoue.
allow sur un sous-réseau puis deny all Vous fermez le site à tout Internet, donc à vos visiteurs. Réservez ce schéma aux URL d’administration.
Bannir des pays entiers par réflexe Beaucoup de faux positifs, et les attaquants louent des machines partout.
Désactiver les journaux « pour la performance » Vous perdez le seul moyen de comprendre ce qui vous arrive.

Une règle simple : toute mesure qui bloque plus large que le motif observé se paiera en clients perdus.

Quand faut-il nous ouvrir un ticket ?

Quand le problème dépasse ce que vous pouvez régler sur la machine : lien saturé, attaque longue, ou milliers d’adresses.

Ouvrez un ticket si :

  • la machine reste inaccessible malgré ces réglages ;
  • le trafic sature le lien réseau avant même d’atteindre Nginx ;
  • l’attaque dure et provient de milliers d’adresses différentes.

Joignez au ticket les extraits de logs de l’étape 1 et la fenêtre horaire concernée. C’est ce qui nous permet d’agir en amont, sur le réseau, là où vous ne pouvez pas intervenir.

Cet article vous a-t-il été utile ?