Playawale : Fin de l’Open Data sauvage
Comment j’ai découvert (et bloqué) l’aspiration massive de mes données sur PlayAwale Ou : pourquoi il ne suffit jamais d’une seule serrure pour protéger une porte. En bref Des robots automatisés ont…
- 8 min de lecture
- mis à jour le 4 septembre 2026
Comment j’ai découvert (et bloqué) l’aspiration massive de mes données sur PlayAwale
Ou : pourquoi il ne suffit jamais d’une seule serrure pour protéger une porte.
En bref
Des robots automatisés ont pillé pendant un moment les fichiers de replays de parties d’Awalé sur PlayAwale.com, probablement pour constituer un dataset d’entraînement pour une IA. J’ai coupé l’accès, verrouillé le système, et mis en place quatre mesures qui rendent désormais ce genre de pillage lent, coûteux et peu rentable sans jamais gêner les vrais joueurs.
Ce qui s’est passé
PlayAwale, c’est un jeu d’Awalé en ligne que j’ai développé seul, avec de nombreuses parties enregistrées. Chaque partie jouée contre l’IA peut être revue sous forme de « replay » : un fichier qui contient tous les coups joués, consultable via une URL du type playawale.com/replay_ai.php?id=2989.
Ces replays étaient exposés en « open data » : n’importe qui pouvait récupérer les données brutes au format JSON, sans restriction. Une transparence assumée au départ, je ne pensais pas que ça intéresserait quelqu’un d’autre que les joueurs eux-mêmes.
En analysant mes statistiques de fréquentation, j’ai repéré une anomalie : plus de 1000 visites quotidiennes inhabituelles. En remontant les journaux d’accès du serveur (les « logs »), le tableau est devenu clair : des requêtes répétitives, à intervalles réguliers, avec des signatures qui ne ressemblent pas à un comportement humain. Un bot était en train d’aspirer mes fichiers en boucle.
Pour les curieux, ce que dit une « signature non-humaine » : un visiteur humain clique, hésite, revient en arrière, charge des images, un peu de CSS, du JavaScript. Un script d’aspiration, lui, tape uniquement l’URL du fichier de données, à un rythme mécanique, souvent sans jamais charger le reste de la page. C’est ce contraste qui trahit le bot dans les logs.
Comment le pillage a été mené
Le scénario est classique dans son déroulé, mais soigné dans son exécution :
- Exploration. Le bot a d’abord scanné l’arborescence du site pour lister toutes les URLs de replays possibles. J’ai commis une erreur qui lui a beaucoup facilité la tâche : mon index de parties utilisait une simple numérotation (
id=2200,2201,2202…). Autant laisser un annuaire trié par ordre alphabétique à quelqu’un qui veut tout recopier. - Extraction. Le bot a ensuite ciblé directement mes générateurs de fichiers JSON, qui livraient les données de chaque partie sans vérification particulière.
- Moissonnage. En envoyant des requêtes simultanées, il a téléchargé l’intégralité des coups joués, vraisemblablement pour construire un jeu de données destiné à entraîner une intelligence artificielle.
Pour passer inaperçu, le script simulait des connexions mobiles légitimes via ce qu’on appelle des « terminaux fantômes » probablement un service payant de « device farm » (une ferme de vrais ou faux téléphones utilisée pour générer du trafic qui ressemble à du trafic humain, dispersé sur des dizaines d’adresses IP différentes). Une remarque au passage : si l’auteur avait investi cet argent dans un café pour discuter d’une collaboration, ça lui aurait coûté moins cher et ça m’aurait évité une nuit blanche.
Les mesures d’urgence, cette nuit-là
Avant de construire quoi que ce soit de fin, il fallait arrêter l’hémorragie :
- Coupure de l’export JSON public, le temps de reprendre la main.
- Analyse des accès pour identifier les signatures et les horaires de passage des robots.
- Blocage serveur des adresses suspectes, directement à la source.
- Verrouillage cryptographique du système de replay : l’accès aux flux de données nécessite désormais une clé dynamique générée par signature HMAC, ce qui rend une aspiration automatisée simple inopérante.
- Blocage du réseau Tor, qui permettait de masquer facilement l’origine des requêtes. Je suis conscient que ça pénalise aussi des utilisateurs légitimes soucieux de leur vie privée, c’était un compromis nécessaire pour isoler les flux suspects rapidement.
Pour les curieux, HMAC, en une phrase : c’est une technique cryptographique qui permet de « signer » une donnée avec une clé secrète, de sorte qu’on puisse vérifier que la donnée n’a pas été fabriquée ou modifiée par quelqu’un qui ne connaît pas la clé. Sans la clé, impossible de générer une signature valide, donc impossible de forger une requête acceptée par le serveur.
Le problème de fond : des identifiants trop prévisibles
Une fois l’urgence gérée, un problème structurel restait entier : même verrouillé, le système gardait des identifiants numériques qui se suivaient (2200, 2201, 2202…). Or les robots continuaient à les utiliser dans l’URL malgré les premières mesures. Ça laissait deux failles ouvertes :
- Un script pouvait toujours aspirer tout le catalogue simplement en incrémentant le numéro.
- Un script pouvait appeler l’API JSON directement, sans jamais passer par une vraie page du site, donc sans jamais se comporter comme un visiteur.
J’ai donc ajouté quatre mesures complémentaires, indépendantes les unes des autres.
1. Des identifiants opaques, plus de suite logique
En clair : l’identifiant visible dans l’URL n’est plus un simple numéro qui se suit, mais un code qui ressemble à g2smcjad. Deux parties consécutives (par exemple la 2200 et la 2201) obtiennent des codes totalement différents, sans aucun lien visible entre eux. Impossible de deviner « le suivant » en incrémentant.
Pour les curieux : le code est généré côté serveur par un chiffrement réversible, un réseau de Feistel combiné à une signature HMAC-SHA256, le résultat étant encodé en base32 pour rester lisible dans une URL. Le chiffrement est réversible uniquement côté serveur, grâce à une clé secrète que personne d’autre ne détient : le serveur peut retrouver l’ID numérique interne à partir du jeton, mais personne ne peut faire l’inverse ni deviner un jeton valide sans la clé.
2. Un cookie de « preuve de passage »
En clair : quand vous visitez une page de replay normalement, votre navigateur reçoit une sorte de tampon d’entrée invisible. Les données de la partie ne s’affichent que si ce tampon est présent et valide. Un script qui tape directement l’adresse du fichier de données, sans jamais avoir chargé la vraie page, n’a pas ce tampon et se fait refuser l’accès.
Pour les curieux : ce « tampon » est un cookie signé par HMAC, posé à chaque chargement de la page de replay. Les endpoints API qui renvoient les données de partie vérifient sa présence et sa signature, et répondent 403 (accès refusé) à toute requête qui ne le présente pas. Ça bloque spécifiquement le cas où un script tape l’API en direct sans jamais charger la page HTML autour.
3. Un quota par visiteur sur les anciennes adresses
En clair : pour ne pas casser les liens déjà partagés par des joueurs (sur les réseaux sociaux, dans des forums, etc.), les anciennes adresses numériques continuent de fonctionner mais avec une limite : 20 parties différentes maximum par adresse IP sur 24 heures. Revoir plusieurs fois la même partie ne compte pas dans ce quota, donc un joueur normal ne remarquera jamais la restriction. Au-delà, le serveur répond que « cette adresse n’existe plus » (que ce soit un moteur de recherche ou un script qui la demande).
Pour les curieux : la réponse technique renvoyée est un code HTTP 410 Gone, délibérément choisi plutôt qu’un simple 403 ou 404, il signale explicitement aux robots légitimes (moteurs de recherche compris) que la ressource a été retirée intentionnellement et durablement, ce qui encourage sa désindexation. Les nouveaux jetons opaques, eux, ne sont soumis à aucun quota : c’est le format ancien, potentiellement exploitable, qui est bridé.
4. Un traitement séparé pour le référencement (SEO)
En clair : certaines parties mises en avant (par exemple dans des classements) doivent rester visibles sur Google. Pour elles, l’ancienne adresse redirige automatiquement et de façon permanente vers la nouvelle adresse sécurisée. Toutes les autres anciennes pages sont marquées comme « à ne pas indexer », pour pousser progressivement les moteurs de recherche légitimes vers les nouvelles URLs.
Pour les curieux : la redirection utilise un code HTTP 301 (redirection permanente), qui indique aux moteurs de recherche de transférer la valeur de référencement vers la nouvelle URL. Les pages non prioritaires reçoivent une balise noindex.
Pourquoi empiler quatre mesures plutôt que de miser sur une seule
Aucune de ces quatre mesures n’est, prise isolément, infranchissable. Un scraper suffisamment motivé qui charge d’abord la page avant d’appeler l’API contourne le cookie de preuve de passage. Un scraper qui distribue ses requêtes sur des centaines d’adresses IP contourne le quota. C’est assumé : ce n’est pas un verrou absolu, c’est un ralentisseur.
Mais empilées, ces mesures changent le calcul économique du pillage. Chaque étage supplémentaire demande plus d’ingénierie, plus de temps, plus de ressources pour un volume de données de plus en plus réduit, de plus en plus lentement. À un moment, aspirer 20 000 parties devient plus cher que de simplement demander l’accès. C’est le principe de la défense en profondeur : pas une solution miracle unique, mais plusieurs filtres complémentaires, dont aucun ne gêne un joueur qui, lui, se contente de jouer et de revoir ses parties.
Un mot pour finir
Ce n’est pas l’usage des données en lui-même qui pose problème c’est la méthode. Si quelqu’un travaille sur une IA en deep learning et a besoin de datasets de parties d’Awalé pour l’entraînement, une collaboration honnête sera toujours préférable au pillage silencieux. La porte reste ouverte ; il suffit de frapper.