Créer un système de CAPTCHA dynamique et sécurisé avec NestJS
Plongée au cœur de Math & Shapes Captcha, une API anti-bot innovante générant des SVGs dynamiques avec validation JWT.
Math & Shapes Captcha 🛡️🤖
Les systèmes anti-bots classiques comme Google reCAPTCHA ou Cloudflare Turnstile sont très efficaces, mais ils s'accompagnent souvent de compromis sur la confidentialité des utilisateurs (tracking) et l'indépendance de l'architecture.
C'est ce constat qui m'a poussé à développer Math & Shapes Captcha, une API moderne, légère et 100% open-source, développée avec NestJS.
Pourquoi un CAPTCHA maison ?
L'objectif était de concevoir un système qui :
- Respecte la vie privée : Aucun script tiers ou cookie traceur n'est injecté chez le client.
- Est résilient face aux bots basiques (OCR) : Les défis sont générés sous forme d'images SVG fortement altérées (bruit, lignes parasites, rotations aléatoires).
- Résiste aux attaques par rejeu (Replay Attacks) : Grâce à l'utilisation de jetons éphémères et de JSON Web Tokens (JWT) chiffrés.
🛠️ Architecture Technique
Le backend est bâti sur une stack robuste :
- Framework : NestJS (TypeScript)
- Génération Graphique : SVG dynamique généré à la volée.
- Sécurité : JWT (JSON Web Tokens) pour valider l'authenticité de la résolution.
- Performance : In-Memory Cache pour stocker temporairement l'état des challenges et appliquer un Rate-Limiting strict.
- Déploiement : Conteneurisation via Docker.
Comment fonctionne la validation ?
Le workflow est conçu pour être robuste face aux scripts automatisés :
- Génération : Le frontend demande un challenge. Le backend génère une équation mathématique aléatoire (ex:
15 + 7) ou un défi géométrique. - Obfuscation : Le défi est converti en une image SVG bruitée. Le backend stocke la réponse attendue dans son cache en mémoire avec un identifiant unique (
challengeId) et une très courte durée de vie (ex: 2 minutes maximum). - Résolution : L'utilisateur soumet sa réponse avec le
challengeIdvia le front. - Validation JWT : Si la réponse est correcte, le backend détruit immédiatement le challenge du cache (pour prévenir le double usage) et signe un JWT de validation. Ce JWT sera ensuite transmis par le frontend lors de la soumission du formulaire final (ex: formulaire de contact), agissant comme un "passeport" vérifiable par le backend final.
Les défis liés à l'OCR (Reconnaissance Optique)
L'un des défis majeurs dans la création d'un CAPTCHA visuel est d'empêcher les outils de Reconnaissance Optique de Caractères (OCR), comme Tesseract, de lire le texte.
Pour contrer cela, l'API génère des chemins vectoriels complexes : les nombres ne sont pas de simples balises <text> SVG (qui seraient triviales à parser), mais des formes déformées avec des lignes de bruit dynamiques de la même couleur qui s'entrecroisent avec le contenu principal. L'ajout d'une inversion de couleurs dynamique selon le thème de l'utilisateur (Dark Mode) rajoute une couche supplémentaire de perturbation.
Découvrir le projet
Vous pouvez tester l'intégration de ce CAPTCHA en temps réel sur la page d'accueil de ce portfolio (lors de la simulation de système verrouillé) ou sur la section de Contact pour valider l'envoi du message !
🔗 Code Source (GitHub) : mmct13/captcha-perso
🔗 Démo API live : Documentation API
N'hésitez pas à jeter un œil au code et à proposer des améliorations. En cybersécurité, la lutte contre les bots est un jeu du chat et de la souris qui ne s'arrête jamais !