Une vague de scrapers sur l’offre gratuite de Cloudflare : ce qui l’a arrêtée, et ce que nous avons laissé désactivé
Opérations
Un matin, l’un de nos sites de fiches produits a cessé de s’ouvrir. Cloudflare affichait une erreur 524 aux visiteurs, l’origine mettait deux à six minutes par page, et rien ne nous a alertés pendant environ dix heures. La cause : un scraper passant par des proxys résidentiels à environ 225 requêtes par seconde.
La forme de la vague
- Des milliers d’adresses, une à trois requêtes chacune. Des connexions internet résidentielles aux États-Unis, en Espagne, en France, au Brésil, au Royaume-Uni et ailleurs, le type de trafic loué par un réseau de proxys résidentiels.
- User agents Chrome sur Mac, avec des numéros de version allant de 103 à 151.
- Presque jamais de cookie ni de Referer. Sur 2 697 requêtes échantillonnées côté serveur, 4 portaient un cookie et 4 un Referer.
- Deux types de clients. Environ la moitié n’envoyait pas d’en-têtes
Sec-Fetch-*ni de client hints : un script avec une chaîne user agent copiée. L’autre moitié envoyait des en-têtes de navigateur complets : un navigateur headless.
Chaque page était rendue pour chaque requête, de sorte que chaque worker mettait en file des centaines de rendus et atteignait sa limite CPU.
Pourquoi les limites par adresse ne pouvaient pas aider
Une limitation de débit compte les requêtes par adresse. Avec une à trois requêtes provenant de chacune des milliers d’adresses, aucune adresse n’approche jamais d’une limite. Bloquer des pays aurait bloqué nos visiteurs. Ce que le scraper ne pouvait pas simuler à moindre coût, c’était de se comporter comme un navigateur ayant déjà visité le site.
À la périphérie de Cloudflare : trois règles gratuites
L’offre gratuite autorise cinq règles WAF personnalisées par zone. Nous en avons utilisé trois, toutes avec un défi géré plutôt qu’un blocage, afin qu’une personne bloquée par erreur puisse cliquer pour passer :
- Navigateur factice : une requête GET dont l’user agent contient
Chrome/et qui n’a pas d’en-têteSec-Fetch-Mode. Tout Chrome depuis 2019 l’envoie. - Clouds de scrapers : une demande de page provenant des réseaux d’Alibaba, Tencent et Huawei Cloud, d’où provenait une grande partie de ce que nous avons soumis à un défi.
- Urgence, désactivé par défaut : une requête GET sans aucun cookie et sans Referer. Une personne ayant déjà visité le site, ou arrivant via un lien, passe sans être dérangée ; un scraper qui ne conserve pas de cookies rencontre un défi à chaque requête. Nous ne l’activons que pendant une vague, car il soumet aussi à un défi quelqu’un qui tape l’adresse dans un navigateur neuf.
Les trois laissent passer les robots vérifiés de Cloudflare, les user agents qui se déclarent comme robots, nos propres adresses, les chemins API et webhook, ainsi que les fichiers qui ne sont pas des pages. Deux jours plus tard, l'inondation continuait : en une heure, la règle de faux navigateurs a soumis plus de 10 000 requêtes à un défi. Les 10 000 événements renvoyés par Cloudflare par requête provenaient de 9 627 adresses, aucune n'ayant plus de 4.
À l'origine : une porte dans l'application
La partie headless possède des en-têtes de navigateur complets, de sorte que les règles de bordure ne la détectent pas à elles seules lorsque la règle d'urgence est désactivée. Dans l'application elle-même, nous avons placé un petit middleware devant le moteur de rendu de page :
- un user agent Chrome sans
Sec-Fetch-Modeni client hints reçoit une 403 avant tout traitement ; - un inconnu, sans aucun de nos cookies et sans Referer, n'est servi que si le worker a de la capacité disponible, à quelques pages par seconde. Au-delà, une page 503 de 400 octets définit un cookie et recharge après deux secondes. Une personne obtient la page au deuxième essai ; un scraper qui ne conserve pas les cookies ne l'obtient jamais.
Durant sa première minute, la porte a refusé environ 6 700 faux navigateurs et écarté environ 6 700 inconnus, tout en servant aux inconnus environ 9 pages par seconde. Les requêtes lentes sont tombées à zéro, le CPU des workers est passé de leur limite à 12 à 15 pour cent, et leur mémoire de 4 à 5 Go chacun à 0,65 Go.
Ce que nous avons laissé désactivé
- Bot Fight Mode. Il soumet le trafic automatisé à un défi et ne peut être contourné par une règle personnalisée sur le plan Free, et il a bloqué les webhooks de notre prestataire de paiement.
- Le mode Under Attack pour toute la zone. Il fait passer chaque visiteur, client API et webhook par la page interstitielle. La règle d'urgence fait le même travail uniquement pour les demandes de pages des inconnus.
- La règle de limitation de débit du plan Free. Elle compte par adresse, ce que cette inondation ne déclenche jamais.
- Le blocage des crawlers IA. Nous voulons être trouvés par les assistants de recherche IA, et ces crawlers n'étaient pas le problème.
À retenir
Une inondation via des proxys résidentiels se repère facilement à ce qui lui manque : les en-têtes fetch du navigateur, les cookies et les Referers. Soumettez-la à un défi à la bordure, maintenez les inconnus dans les limites de ce que vos workers peuvent rendre, et assurez-vous que quelque chose à l'extérieur du serveur remarque quand une page cesse de s'ouvrir. Night Watch regroupe les trois : la surveillance, les règles avec un basculement automatique pour la règle d'urgence, et la porte pour les applications web Python.