Votre serveur subit l'attaque d'un scraper (load à 37) : le bloquer avec .htaccess sans bloquer les vrais clients

par Luca Cavallini Cas d'assistance
Votre serveur subit l'attaque d'un scraper (load à 37) : le bloquer avec .htaccess sans bloquer les vrais clients

Le symptôme

Le load average du serveur, le chiffre qui résume combien de requêtes attendent d'être traitées, grimpe en quelques minutes à une valeur hors norme : de quelques points, normal pour une boutique en bonne santé, à plus de 30. Le site répond par à-coups, des pages qui se chargeaient instantanément mettent maintenant plusieurs secondes, et à certains moments il ne répond plus du tout. Il n'y a eu aucun déploiement, aucune modification du catalogue, aucune campagne publicitaire lancée à ce moment-là : le trafic « normal » des vraies personnes n'a pas changé, quelque chose d'autre s'y est ajouté.

Regarder le log d'accès en direct (tail -f sur le log Apache ou Nginx, filtré sur les dernières minutes) rend la cause évidente en quelques secondes : des centaines de requêtes par minute sur les pages catégorie et les fiches produit, venant d'une poignée d'adresses IP qui appartiennent à un fournisseur de cloud computing, et non à des connexions résidentielles ou mobiles. C'est un scraper, un programme qui télécharge systématiquement le catalogue, pas un pic de trafic humain.

Ce que cela semblait être, et n'était pas

La première idée, la plus évidente, consiste à bloquer les adresses IP qui apparaissent dans les logs : cela semble la solution la plus directe, et pendant les premières minutes cela paraît même fonctionner, la charge baisse dès que ces IP ne reçoivent plus de réponse. Le problème revient peu après : le scraper est coordonné sur plusieurs adresses du même fournisseur cloud, en rotation, et chaque IP bloquée est remplacée par une nouvelle en quelques minutes. Bloquer les IP une par une, dans ce scénario, est une course perdue d'avance : vous passez votre temps à ajouter des lignes à une liste que le scraper contourne simplement en changeant d'IP.

Il y a pourtant un détail que la rotation des IP ne cache pas : chaque requête du scraper, quelle que soit l'IP qui l'envoie à un instant donné, déclare le même petit ensemble d'identités de navigateur (le user agent), et plus précisément des versions de Chrome vieilles de plusieurs années, exactement le genre de chaîne qu'un vrai navigateur met à jour automatiquement et qu'on ne s'attend plus à voir circuler. La rotation cache l'adresse, pas la signature.

La vraie cause et le choix du blocage

Un blocage efficace, dans ce scénario, combine les deux critères dans la même règle, en haut du fichier .htaccess de la boutique, juste après RewriteEngine on, pour que la requête soit rejetée par Apache avant même d'atteindre PrestaShop et la base de données : c'est la différence entre répondre par une erreur pour un coût quasi nul, et faire tourner quand même toute la pile applicative pour une requête qui sera de toute façon rejetée.

# IP connues du fournisseur cloud concerné
RewriteCond %{REMOTE_ADDR} ^203\.0\.113\.10$ [OR]
RewriteCond %{REMOTE_ADDR} ^203\.0\.113\.11$
RewriteRule ^ - [F,L]

# Signature User-Agent du scraper (versions de Chrome datées, utilisées sur des IP en rotation)
RewriteCond %{HTTP_USER_AGENT} "Chrome/87\.0\.4280\.141" [OR]
RewriteCond %{HTTP_USER_AGENT} "Chrome/61\.0\.3163\.100" [OR]
RewriteCond %{HTTP_USER_AGENT} "Chrome/74\.0\.3729\.169"
RewriteRule ^ - [F,L]

(Les adresses ci-dessus sont des exemples : dans le cas réel, il y avait quatre IP d'un même fournisseur cloud, identifiées à partir du trafic du moment. Elles doivent toujours être tirées du trafic réel en direct, jamais copiées d'une liste trouvée ailleurs.)

C'est le blocage par signature qui résiste réellement à la rotation : même quand le scraper change d'IP, la chaîne du user agent reste la même jusqu'à ce qu'il la change aussi, et à ce moment-là il faut mettre la règle à jour, pas repartir à la chasse aux adresses une par une.

Le vrai risque de ce type de blocage

Bloquer par signature, et pas seulement par adresse, est plus efficace, mais cela augmente aussi le risque d'un effet de bord que personne ne vérifie tant qu'il ne lui est pas arrivé : attraper un vrai client dont l'appareil déclare par hasard quelque chose qui ressemble à la signature bloquée. Ce n'est pas un risque théorique : sur la même boutique, avec un filtre différent mais la même logique de fond (reconnaître des programmes automatiques à partir d'une chaîne), la première version de cette règle attrapait aussi le nom d'une marque de téléphones légitime, et PrestaShop, chaque fois qu'il décide qu'une requête vient d'un robot, ignore en silence l'ajout au panier : le client voyait « c'est fait », le panier restait vide, aucune erreur dans aucun log. L'histoire complète, avec les chiffres de ce cas, se trouve dans cet article ; il vaut la peine de le lire avant d'écrire un blocage par signature, parce que c'est le vrai danger de cette technique, et presque personne ne le vérifie avant d'en activer un.

Pour cette raison, avant d'activer un blocage par signature, il faut vérifier explicitement qu'il n'attrape pas de trafic légitime. Dans le cas qui a donné naissance à cette règle, trois catégories de trafic ont été vérifiées une par une avant de considérer le blocage comme sûr :

  • l'accès au back-office depuis une session administrateur déjà authentifiée (doit rester hors du blocage : un pare-feu au niveau du .htaccess ne peut pas distinguer un administrateur connecté d'un visiteur anonyme, sinon par l'URL qu'il appelle) ;
  • une vraie visite depuis un smartphone, avec le user agent authentique du navigateur mobile (doit rester hors du blocage : un blocage trop large sur les « anciennes versions de Chrome » peut aussi attraper des navigateurs mobiles légitimes aux numéros de version inattendus) ;
  • les requêtes automatiques légitimes d'un service tiers intégré à la boutique, par exemple un transporteur ou un système de paiement qui interroge l'API de la boutique avec son propre user agent déclaré (doit rester hors du blocage : c'est de l'automatisation, mais de l'automatisation voulue).

Ce n'est qu'après avoir confirmé qu'aucune de ces trois catégories ne tombait dans le blocage que la règle a été considérée comme sûre à laisser active.

Comment vérifier que le blocage tient

  • En ligne de commande, avec curl, envoyez une requête qui déclare l'un des user agents bloqués : elle doit renvoyer 403. Envoyez-en une avec un user agent normal et à jour : elle doit renvoyer 200, sur la page d'accueil, une catégorie et une fiche produit.
  • Surveillez la charge du serveur dans les minutes qui suivent l'activation du blocage : elle doit baisser régulièrement, pas par à-coups, tant que le scraper n'a pas encore changé d'IP ou de signature. Une charge qui remonte après une première baisse est le signal que la signature a changé et que la règle doit être mise à jour.
  • Vérifiez dans les logs, pendant quelques jours après l'activation, que les trois catégories de trafic légitime listées ci-dessus continuent de fonctionner normalement : c'est la vérification qui évite réellement le problème du client bloqué à tort, pas une chose à faire une fois puis à oublier.
  • Gardez une sauvegarde du fichier .htaccess d'avant le blocage, avec un retour arrière prêt (une vraie copie, pas une commande dont vous vous souviendrez plus tard) : si quelque chose tourne mal, le moyen le plus rapide de retrouver une boutique qui fonctionne est de restaurer le fichier, pas de corriger la règle sous pression avec le site en panne.

La boutique sur laquelle ce blocage a été appliqué reste volontairement anonyme. Un blocage au niveau du .htaccess, par IP et par signature, est la bonne réponse quand un serveur est attaqué en ce moment même et a besoin d'un soulagement immédiat : il ne coûte presque rien, parce qu'il répond avant que PrestaShop n'ait à faire quoi que ce soit. Mais c'est un geste chirurgical, pas une solution permanente : si les adresses et les signatures changent complètement, une autre approche est nécessaire (par exemple un blocage fondé sur le débit des requêtes plutôt que sur l'identité). Et surtout, avant de l'activer, vérifiez toujours ce qu'il ne doit PAS attraper, pas seulement ce qu'il doit arrêter. Pour les interventions urgentes de ce type sur une boutique PrestaShop, un résumé des services se trouve sur cette page.

Laisser un commentaire

Les commentaires sont modérés avant publication.

← Blog

Chargement...
Retour en haut