Défendre votre serveur Web contre les attaques par déni de service distribué

En matière de sécurité informatique, il devient rapidement évident que prévenir les attaques informatiques est beaucoup plus difficile que d’attaquer des ordinateurs. Un bon exemple de technique simple pour empêcher un site Web de fonctionner est un déni de service distribué, ou DDoS, attaque dans laquelle un certain nombre d'ordinateurs compromis sur Internet émettent des requêtes Web (ou autre protocole) sur un serveur défaillant. Si la page Web demandée nécessite beaucoup de traitement côté serveur, la charge résultant des demandes combinées empêche le serveur Web de répondre aux demandes légitimes, ce qui refuse le service. Comme Tech-Recipes.com a récemment fait l'objet d'une telle attaque, nous avons pensé que cela pourrait être bénéfique pour d'autres si nous décrivions les étapes que nous avons suivies dans notre réponse.


Remarque: Les informations suivantes concernent les serveurs UNIX exécutant Apache (bien que d'autres plates-formes et logiciels puissent être applicables). Une condition préalable à cette approche nécessite l'utilisation de iptables, ce qui signifie probablement que vous avez besoin d'un accès root au serveur. Par conséquent, cela ne vous aidera probablement pas si vous utilisez un hébergement partagé. Pardon! Dans ce cas, votre meilleur choix est de contacter votre fournisseur de services Internet (bonne chance) car il est dans son intérêt d'empêcher les charges élevées sur leurs serveurs partagés, bien qu'il soit probable qu'ils désactivent temporairement vos services de domaine, ce qui est certainement le cas. pas la meilleure solution de votre point de vue.

Pour minimiser l'impact d'une attaque par déni de service, vous devez être informé des problèmes liés à votre serveur Web en temps quasi réel. Plusieurs services de surveillance de serveur sont disponibles. Nous utilisons Pingdom et SiteUptime. En utilisant ces services, nous avons des notifications redondantes de toute interruption de service envoyées à nos téléphones portables par SMS et à plusieurs adresses électroniques (aucune d'entre elles n'étant gérée par nos serveurs surveillés, bien sûr). En utilisant ces services, nous sommes informés dans la minute qui suit une demande infructueuse adressée à nos serveurs de production.

Avant de mettre en œuvre des techniques anti-DDoS spécifiques ou de faire appel à un service de protection DDos, il est conseillé de s’assurer que le problème est bien une attaque DDoS. Les services peuvent ne pas répondre à une demande pour un certain nombre de raisons, notamment l'exécutable exécutant le service en train de mourir inopinément, le FAI hébergeant le serveur confronté à une panne de réseau ou de serveur, ou à un autre problème de correction automatique dans la matrice. Pour déterminer si la défaillance du service est due à un DDoS et pour collecter les informations nécessaires pour prendre des mesures contre l'attaque, vous devez commencer par fouiller.

Vous devez accéder à votre fichier access_log, le fichier journal contenant une entrée de texte pour chaque demande adressée à votre serveur Web. Ce fichier peut masquer de nombreux endroits et cela dépend de la configuration de votre serveur. En cas de doute, vous pouvez consulter la documentation du fournisseur de services Internet (recherche du journal d'accès). Les données du journal peuvent être accessibles via une console Web, mais elles sont optimales si vous disposez d'un accès shell à votre serveur. Si l'aide en ligne de votre fournisseur de services Internet n'est pas très utile pour trouver le journal des accès, vous pouvez utiliser la commande UNIX find.

Une fois que vous avez trouvé votre journal d’accès, placez-vous dans le répertoire contenant le journal et exécutez la commande tail avec les options -f:

tail -f access_log

La commande tail affichera seule les 10 dernières lignes du fichier spécifié, puis se fermera. L'option -f indiquera à tail de continuer à fonctionner après l'affichage des 10 dernières lignes et d'afficher les lignes suivantes ajoutées au fichier. Vous êtes susceptible de voir une multitude d'entrées. Si vous ne voyez aucun message de journal après la valeur par défaut 10, vous recherchez soit un fichier incorrect, soit le serveur Web est mort, soit ne détectez aucun trafic. Il est possible qu'un serveur puisse héberger plusieurs sites Web et que chacun puisse avoir un fichier access_log distinct. Assurez-vous donc que vous choisissez le bon. Si le service est mort, ressuscitez-le selon le mécanisme approprié. Nous allons supposer à partir de maintenant que vous voyez une tonne de messages de journal d'accès qui se ressemblent beaucoup (frappant probablement la même URL) et qui n'ont pas de référent valide ou aucun référent (si le référant est slashdot.org ou digg.com, eh bien, alors vous pouvez être à la fois heureux et triste que le trafic, même si le serveur est paralysant, est légitime) et que vous avez plusieurs adresses IP différentes. Au cours de notre siège récent, il y avait tellement de demandes fictives que très peu de demandes légitimes ont été transférées dans le fichier access_log. Voici quelques lignes de notre access_log lors de l'attaque:

220.255.7.204 - - [07 / Jul / 2008: 19: 28: 18-0600] "GET /modules.php?name=Forums&file=index HTTP / 1.1" 200 0 "-" "Mozilla / 4.0 (compatible; MSIE 6.0 ; Windows NT 5.1; SV1; .NET CLR 1.1.4322) "

220.255.7.209 - - [07 / Jul / 2008: 19: 28: 18-0700] “GET /modules.php?name=Forums&file=index HTTP / 1.1” 200 0 “-” “Mozilla / 4.0 (compatible; MSIE 6.0) ; Windows NT 5.1; SV1; .NET CLR 1.1.4322) ”

220.255.7.208 - - [07 / Jul / 2008: 19: 28: 18-0600] “GET /modules.php?name=Forums&file=index HTTP / 1.1” 200 0 “-” “Mozilla / 4.0 (compatible; MSIE 6.0) ; Windows NT 5.1; SV1; .NET CLR 1.1.4322) ”

71.232.78.53 - - [07 / Jul / 2008: 19: 28: 19 - 0700] "GET /modules.php?name=Forums&file=index HTTP / 1.1" 200 14313 "-" "Mozilla / 4.0 (compatible; MSIE 7.0 ; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) ”

Si vous ne connaissez pas bien la structure par défaut du fichier access_log d'Apache, la première valeur est l'adresse IP source de la demande, puis la date et l'heure de la demande sont entre crochets et la première chaîne entre guillemets est la demande HTTP. fabriqué. Dans notre exemple, la demande était toujours la même: "GET /modules.php?name=Forums&file=index HTTP / 1.1" - une requête GET de l'URL (/modules.php?….) Et du protocole HTTP utilisé (1.1 ).La partie de l'URL utilisée est importante car c'est la seule chose que nous pouvons utiliser pour identifier les adresses IP incriminées. La deuxième chaîne entre guillemets est l’URL de renvoi; dans notre cas, il n’en existe pas, elle s’affiche sous la forme «-», ce qui donne à penser qu’il s’agit d’une attaque par DDoS. La chaîne restante décrit la plate-forme et le logiciel qui a fait la demande et ne nous est pas très utile ni utile car elle peut facilement être falsifiée.

Maintenant que nous savons qu'une attaque par DDoS est en cours, nous avons besoin d'une liste des adresses IP impliquées dans l'attaque afin de bloquer leurs demandes ultérieures avec iptables. Dans l'exemple ci-dessus, access_log, je sais que le composant URL demandé «/modules.php?name=Forums&file=index» peut être utilisé pour effectuer une recherche dans le journal access_log. Parce qu'il contient des caractères spéciaux comme & et? que la plupart des interpréteurs de commandes UNIX interprètent comme quelque chose de très différent, il est judicieux de mettre la chaîne de recherche entre guillemets dans toutes les commandes qui l'utilisent. La commande suivante ne saisira dans access_log que les lignes correspondant au composant URL ci-dessus et renverra une liste d'adresses IP qui l'ont demandée et le nombre de fois où chaque adresse IP a effectué la demande, triée par nombre.

fgrep "/modules.php?name=Forums&file=index" access_log | cut -d \ -f1 | trier -n | uniq -c | trier -rn

La commande fgrep est un grep rapide qui ne recherche pas d'expressions régulières et peut détruire beaucoup plus efficacement des fichiers journaux volumineux. Si votre système ne l’a pas pour une raison insondable, remplacez fgrep par old grp. Remplacez le nom de votre journal d'accès s'il est différent de access_log. Notez qu'il y a deux espaces après la barre oblique inverse dans l'option cut -d \. Cette chaîne de commandes va extraire les lignes correspondantes dans access_log (fgrep), extraire le premier champ séparé par des espaces (couper), les trier numériquement (trier -n), les regrouper pour faire une liste d'adresses IP uniques et compter les occurrences. (uniq), et triez-les numériquement dans l’ordre inverse afin que les adresses IP avec les décomptes les plus élevés arrivent en premier. Voici un exemple de la sortie:

21889 71.232.78.53
17181 220.255.7.208
16162 220.255.7.209
16142 220.255.7.204

Vous êtes susceptible de voir deux groupes, des adresses IP avec un grand nombre (des centaines, des milliers) de requêtes et d'autres avec quelques, voire des dizaines de requêtes. Lorsque vous choisissez le nombre de demandes qui sépare les deux groupes, faites attention car vous ne voulez pas bloquer les demandes légitimes. Si vous commencez à bloquer les adresses IP en haut de la liste, vous saurez que les chiffres changent et deviennent des valeurs apparentes légitimes, comme un saut de plusieurs centaines de hits à quelques dizaines de hits. Si vous le pouvez, copiez le résultat de la commande ci-dessus dans un éditeur de texte pour le garder à portée de main. Une remarque, si votre access_log ne fait pas l'objet d'une rotation fréquente (son contenu est copié dans un autre emplacement et éventuellement compressé), il peut devenir énorme. Vous pouvez utiliser la commande tail d'une manière différente pour accélérer l'exécution de cette commande, ce que votre serveur en crise appréciera probablement. La commande "tail -10000 access_log" prendra les 10 000 dernières lignes de access_log et continuera à les traiter (vous pouvez les modifier). à un nombre de votre choix):

tail -10000 access_log | fgrep "/modules.php?name=Forums&file=index" | cut -d \ -f1 | trier -n | uniq -c | trier -rn

Maintenant que vous savez quelles adresses IP vous devez bloquer, il est grand temps de définir la loi iptable. Le système iptables est capable de nombreuses opérations différentes et, heureusement pour nous, le blocage d’une adresse IP unique est l’une des configurations les plus simples. Pour bloquer toutes les demandes d'une adresse IP telle que 71.232.78.53, utilisez la commande suivante:

iptables -A ENTREE -s 71.232.78.53 -j DROP

Si vous n'êtes pas connecté au serveur en tant que root, ajoutez simplement un 'sudo' devant cette commande et indiquez votre mot de passe lorsque vous y êtes invité. Cette commande ajoute une règle temporaire au système iptables pour supprimer tous les paquets provenant de l'adresse IP spécifiée. Cet effet est temporaire dans la mesure où il ne persistera pas après un redémarrage. Si vous souhaitez rendre ces modifications permanentes (probablement pas une bonne idée, mais pas si mal non plus, si vous envisagez de redémarrer sous peu pour libérer toute mémoire perdue), vous pouvez essayer de lancer

/etc/init.d/iptables save

Cette commande fonctionnera et vous indiquera que cela a fonctionné, ou provoquera une erreur. Dans ce dernier cas, vous pouvez répéter les commandes iptables, une par adresse IP, pour les rebloquer.

Si vous avez des demandes provenant d'un certain nombre d'adresses IP dans le même sous-réseau, vous pouvez bloquer le sous-réseau à l'aide d'une commande iptables. Dans notre cas, nous avions un tas d’adresses IP provenant des demandes d’envoi de sous-réseau 220.255.7.0. Plutôt que de répéter la commande iptables plusieurs centaines de fois, le raccourci de sous-réseau pour la commande iptables rend cette tâche beaucoup plus simple:

iptables -A INPUT -s 220.255.7.0/24 -j DROP

Je ne bloquerais pas plus qu'un sous-réseau de classe C à la fois, comme indiqué ci-dessus. Essentiellement, si vous voyez un ensemble de demandes d'adresses IP dans lesquelles les trois premiers chiffres de l'adresse IP sont identiques, ils sont tous dans le même sous-réseau de classe C et vous pouvez les bloquer en utilisant les trois premiers nombres séparés par des points. suivi d'un 0,0 / 24 comme ci-dessus.

Puisqu'une attaque DDoS est peut-être en cours et que plus de machines peuvent prendre part à l'attaque au fil du temps, il vaut peut-être la peine que vous fassiez un script rapide pour bloquer simplement une adresse IP. J'ai écrit le script suivant et l'ai placé dans / usr / sbin / block

#! / bin / bash

iptables -A INPUT -s $ 1 -j DROP

Une fois le fichier en place, rendez-le exécutable avec chmod + x / usr / sbin / block et ensuite l'utiliser comme:

bloc 71.232.78.53

Chaque système est unique, comporte différentes applications et versions d'applications installées à différents endroits. Votre kilométrage peut donc varier en fonction des instructions ci-dessus.