Les attaques de la couche 7 sur les sites incluent les attaques sur la couche serveur Web (nginx, apache, etc.) et les attaques sur la couche serveur d'applications (php-fpm, nodejs, etc.), qui se trouve généralement derrière le serveur proxy (nginx, apache , etc.). Du point de vue du protocole réseau, les deux sont des attaques de la couche application. Mais d'un point de vue pratique, nous devons séparer ces deux cas. Le serveur Web (nginx, apache, etc.), en règle générale, fournit indépendamment des fichiers statiques (images, styles, scripts) et transmet les demandes de contenu dynamique au serveur d'application (php-fpm, nodejs, etc.)). Ce sont ces requêtes qui deviennent des cibles d'attaques, car, contrairement aux requêtes statiques, les serveurs d'applications lorsqu'ils génèrent du contenu dynamique nécessitent plusieurs ordres de grandeur de ressources système plus limitées, ce qu'utilisent les attaquants.
Aussi banal que cela puisse paraître, pour se défendre contre une attaque, il faut d'abord l'identifier. En fait, non seulement les attaques DDoS peuvent entraîner une défaillance du site, mais également d'autres raisons associées aux erreurs des développeurs et des administrateurs système. Pour la commodité de l'analyse, vous devez ajouter le paramètre $ request_time au format de journal nginx (désolé, je n'ai pas d'option avec apache) et consigner les demandes au serveur d'applications dans un fichier séparé:
log_format timed '$remote_addr - $remote_user [$time_local] '
'$host:$server_port "$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" ($request_time s.)';
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
access_log /var/log/ngunx/application_access.log timed;
}
Après avoir reçu les journaux sur le serveur d'applications dans un fichier séparé (sans journaux statiques) et avec le temps de requête en secondes, vous pouvez rapidement identifier le moment où l'attaque commence, lorsque le nombre de requêtes et le temps de réponse commencent à augmenter fortement.
Après avoir identifié l'attaque, vous pouvez passer à la défense.
Très souvent, les administrateurs système tentent de protéger le site en limitant le nombre de requêtes à partir d'une seule adresse IP. Pour ce faire, utilisez 1) la directive nginx limit_req_zone ( voir documentation ), 2) fail2ban et 3) iptables. Bien entendu, ces méthodes doivent être utilisées. Cependant, cette méthode de protection est inefficace depuis 10 à 15 ans. Il y a deux raisons à cela:
1) Le trafic généré par le réseau de bots lors d'une attaque au 7ème niveau peut être moins volumineux que le trafic d'un visiteur ordinaire du site, puisqu'un visiteur ordinaire du site a une requête "lourde" au serveur d'application (php-fpm , nodejs, etc.) il y a environ 100 requêtes "légères" pour télécharger des fichiers statiques qui sont envoyées par le serveur web (nginx, apache, etc.). Iptables ne protège pas contre de telles demandes, car il ne peut restreindre le trafic que par des indicateurs quantitatifs, et ne prend pas en compte la séparation des demandes en statique et en dynamique.
2) La deuxième raison est la distribution du réseau de robots (la première lettre est D dans l'abréviation DDoS). L'attaque implique généralement un réseau de plusieurs milliers de robots. Ils sont capables de faire des demandes moins fréquemment que l'utilisateur moyen. En règle générale, lors de l'attaque d'un site, un attaquant calcule empiriquement les paramètres limit_req_zone et fail2ban. Et configure le réseau de robots pour que cette protection ne fonctionne pas. Souvent, les administrateurs système commencent à sous-estimer ces paramètres, désactivant ainsi les vrais clients, sans grand résultat en termes de protection contre les bots.
Pour réussir à protéger un site contre les attaques DDoS, il est nécessaire que tous les moyens de protection possibles soient utilisés sur le serveur du complexe. Dans mon article précédent sur ce sujet, la protection DDoS au niveau du serveur Webil y a des liens vers des matériaux sur la façon de configurer iptables, et quels paramètres du noyau système doivent être ajustés à la valeur optimale (c'est-à-dire, tout d'abord, le nombre de fichiers ouverts et de sockets). C'est une condition préalable, une condition nécessaire, mais non suffisante pour la protection contre les bots.
De plus, il est nécessaire de construire une protection basée sur la détection des bots. Tout ce qui est nécessaire pour comprendre les mécanismes de détection des bots a été décrit en détail dans l'article historique sur Habré Le module nginx de lutte contre les DDoS de l' auteur kyprizel , et est implémenté dans la bibliothèque du même auteur testcookie-nginx-module
C'est une bibliothèque C et continue d'être développée par une petite communauté d'auteurs. Tous les administrateurs système ne sont probablement pas prêts à compiler une bibliothèque inconnue sur un serveur de production. Si vous devez apporter des modifications supplémentaires au travail de la bibliothèque, cela dépasse complètement la portée d'un administrateur système ou d'un développeur ordinaire. Heureusement, il y a maintenant de nouvelles fonctionnalités: le langage de script Lua qui peut fonctionner sur le serveur nginx. Il existe deux versions populaires de nginx avec un moteur de script Lua intégré: openresty, qui a été initialement inspiré par Taobao, puis Cloudfare, et nginx-extras, qui est inclus avec certaines distributions Linux, telles que Ubuntu. Les deux options utilisent les mêmes bibliothèques, donc peu importe laquelle utiliser.
La protection contre les robots peut être basée sur la détermination de la capacité du client Web à 1) exécuter du code JavaScript, 2) effectuer des redirections et 3) définir des cookies. De toutes ces méthodes, l'exécution du code JavaScript s'est avérée être la moins prometteuse, et je l'ai refusée, car le code JavaScript n'est pas exécuté si le contenu est chargé avec des requêtes d'arrière-plan (ajax), et le rechargement de la page à l'aide de JavaScript déforme le statistiques des transitions vers le site (depuis le titre Referer). Ainsi, il existe des redirections qui définissent des cookies, dont les valeurs sont soumises à une logique qui ne peut pas être reproduite sur le client, et ne permettent pas aux clients d'accéder au site sans ces cookies.
Dans mon travail, je me suis appuyé sur la bibliothèque leeyiw / ngx_lua_anticc, qui n'est actuellement pas en cours de développement, et j'ai continué les améliorations dans mon fork apapacy / ngx_lua_anticc , car le travail de la bibliothèque d'origine ne convenait pas à tout.
Pour faire fonctionner les compteurs de requêtes dans la bibliothèque, des tables de mémoire sont utilisées, qui prennent en charge les méthodes incrémentales, pratiques pour incrémenter les valeurs de compteur et définir les valeurs avec TTL. Par exemple, l'extrait de code suivant incrémente le nombre de demandes provenant d'une seule adresse IP si le client ne dispose pas d'un cookie avec un nom spécifique. Si le compteur n'a pas encore été initialisé, il est initialisé à 1 avec un TTL de 60 secondes. Après avoir dépassé le nombre de requêtes 256 (en 60 secondes), le client n'est pas autorisé à accéder au site:
local anticc = ngx.shared.nla_anticc
local remote_id = ngx.var.remote_addr
if not cookies[config.cookie_name] then
local count, err = anticc:incr(remote_id, 1)
if not count then
anticc:set(remote_id, 1, 60)
count = 1
end
if count >= 256 then
if count == 256 then
ngx.log(ngx.WARN, "client banned by remote address")
end
ngx.exit(444)
return
end
end
Tous les robots ne sont pas dangereux. Par exemple, vous devez ignorer les robots de recherche et les robots des systèmes de paiement qui signalent les modifications des statuts de paiement sur le site. C'est bien si vous pouvez créer une liste de toutes les adresses IP à partir desquelles de telles demandes peuvent provenir. Dans ce cas, vous pouvez créer une liste "blanche":
local whitelist = ngx.shared.nla_whitelist
in_whitelist = whitelist:get(ngx.var.remote_addr)
if in_whitelist then
return
end
Mais ce n'est pas toujours possible. L'un des problèmes est l'incertitude avec les adresses des robots Google. Ignorer tous les robots qui usurpent les robots Google équivaut à supprimer la protection du site. Par conséquent, nous utiliserons le module resty.exec pour exécuter la commande hôte:
local exec = require 'resty.exec'
if ngx.re.find(headers["User-Agent"],config.google_bots , "ioj") then
local prog = exec.new('/tmp/exec.sock')
prog.argv = { 'host', ngx.var.remote_addr }
local res, err = prog()
if res and ngx.re.find(res.stdout, "google") then
ngx.log(ngx.WARN, "ip " .. ngx.var.remote_addr .. " from " .. res.stdout .. " added to whitelist")
whitelist:add(ngx.var.remote_addr, true)
return
end
if res then
ngx.log(ngx.WARN, "ip " .. ngx.var.remote_addr .. " from " .. res.stdout .. "not added to whitelist")
else
ngx.log(ngx.WARN, "lua-resty-exec error: " .. err)
end
end
L'expérience montre qu'une telle stratégie de protection permet de protéger le site d'une certaine classe d'attaques, souvent utilisées à des fins de concurrence déloyale. Comprendre les mécanismes d'attaques et les méthodes de protection permet de gagner beaucoup de temps sur les tentatives infructueuses de défense contre fail2ban, et lors de l'utilisation de la protection tierce (par exemple de Cloudfare), choisissez les paramètres de protection plus délibérément.
apapacy@gmail.com
9 mai 2021