Comment créer un Captcha maison évolutif sous Symfony

Fabien Lemoine
5 min readMay 22, 2021

--

Ou comment épargner à vos utilisateurs de devoir cliquer sur des voitures.

Crédit : Rock’n Roll Monkey via Unsplash

Sécurisez sans importuner

Les systèmes de Captcha sont largement utilisés sur internet afin que nous, humains, prouvions que nous ne sommes pas des robots. Comprendre : des programmes conçus pour réaliser des actions malveillantes. Un tel programme pourrait par exemple tenter de s’inscrire en masse sur des sites internet afin de pouvoir poster des messages publicitaires de façon automatisée.

Ce dispositif de sécurité s’avère donc utile, mais souffre de plusieurs inconvénients :

  • Beaucoup de sites internet utilisent des solutions tierces de Captcha, ouvrant la porte au traçage des utilisateurs notamment par des géants comme Google.
  • Les Captchas les plus répandus sont très, mais alors vraiment très pénibles pour les humains qui eux n’ont rien demandé, au point de décourager certains utilisateurs de persévérer pour utiliser votre application.
  • En particulier, les utilisateurs en situation de handicap peuvent être d’emblée exclus par certains de ces dispositifs.
  • Par effet de rebond, l’utilisation de Captchas peut avoir un impact négatif sur votre taux de conversion.
Vos utilisateurs apprécieront 😡
Préoccupations autour des captchas et du respect de la vie privée via Twitter

Pour répondre à ces problématiques, nous allons voir qu’il est possible d’implémenter une solution maison qui allie le meilleur des deux mondes : se prémunir contre les robots, mais ne pas trop ennuyer ses utilisateurs et ne pas permettre à une solution tierce de tracer ces derniers.

Implémentation avec Symfony

La souplesse du framework Symfony va nous permettre de réaliser une solution maison évolutive.

Prérequis

L’exemple ci-dessous est conçu avec Symfony 3.4+ avec autowire et autoconfig activés, le code peut néanmoins être adapté pour fonctionner avec des versions antérieures.

Objectif

Nous allons créer un nouveau FormType qui proposera à vos utilisateurs de répondre à une question simple. Ce FormType pourra ensuite être ajouté à n’importe lequel de vos formulaires qui s’en trouvera instantanément sécurisé.

Les questions posées seront de ce type :

  • Quelle est la première lettre du mot RUBIGINEUX ?
  • Quelle est la seconde consonne du mot FLAVESCENT ?
  • Quelle est la dernière voyelle du mot AMPHIGOURI ?

L’utilisateur peut très facilement identifier la bonne réponse, sans même avoir besoin de faire le moindre calcul mathématique. La saisie de la réponse est très rapide : elle tient en un seul caractère.

Exemple dans un formulaire d’inscription

Sommaire

  • Création d’un service “dictionnaire de mots”
  • Création des services de génération des questions
  • Création d’un CaptchaType
  • Création d’un thème Twig pour le CaptchaType
  • Gestion de l’internationalisation
  • Utilisation dans un formulaire

Création d’un service “dictionnaire de mots”

Il peut être utilise d’isoler le dictionnaire de mots du reste du code, simplement pour pouvoir le remplacer facilement si besoin. Allons-y.

Le service “dictionnaire”

Note : dans cet exemple il s’agit de mots méconnus et insolites de la langue française. Aucun des mots ne comporte de caractères accentués. Seuls des mots d’au moins 5 lettres ont été retenus.

Création des services de génération des questions

Nous allons maintenant mettre en place plusieurs services pour générer les questions/réponses. Nous avons vu que nous allons poser plusieurs types de questions : position d’une lettre, d’une voyelle, ou d’une consonne dans un mot. Chacun de ces types de question aura son propre service.

Commençons par mettre en place une interface (au sens programmation orientée objet) :

Interface pour les services “questions/réponses”

Nous pouvons maintenant implémenter les services pour les différents types de questions.

Service : question sur la position d’une lettre dans un mot
Service : question sur la position d’une consonne dans un mot
Service : question sur la position d’une voyelle dans un mot

Vous pouvez reprendre les types de questions de votre choix, ou implémenter vos propres types de questions.

Création d’un CaptchaType

Maintenant, nous pouvons utiliser ces services de génération de questions directement dans le FormType qui sera responsable d’afficher celles-ci sous la forme d’un champ texte. Grâce au concept des services taggués de Symfony, nous allons injecter tous les services de génération de questions dans le FormType qui choisira l’un d’entre eux au hasard.

La session est également nécessaire afin de pouvoir stocker la réponse à l’initialisation du formulaire, puis pour contrôler la validité de la réponse saisie par l’utilisateur à la soumission de ce même formulaire. Le FormType assurera la validation de la réponse grâce à la méthode validateCaptcha qui sera exécutée lors de la validation Symfony.

Le CaptchaType

Voici maintenant comment configurer l’injection des services de génération des questions dans le fichier services.yaml :

Configuration des services taggués

Création d’un thème Twig pour le CaptchaType

Créons le thème qui sera utilisé pour afficher le champ Captcha :

Le thème Twig

A noter : l’exemple utilise Bootstrap (compatible version 3+).

Le champ utilisé pour saisir la réponse à la question est de type password, lorsque le champ obtiendra le focus, il sera automatiquement transformé en champ texte, ceci afin de perturber les robots qui ne s’attendent pas à ne devoir saisir qu’un seul caractère dans un champ password.

Il faut ensuite déclarer le thème personnalisé Twig dans la configuration :

Configuration des thèmes Twig

Gestion de l’internationalisation

Le service de génération des questions se base sur des clés de traduction. Ajoutons ces traductions :

Traductions françaises
Traductions anglaises

Votre Captcha est désormais prêt à l’emploi !

Utilisation dans un formulaire

Il vous reste maintenant à ajouter votre nouveau champ Captcha aux formulaires que vous souhaitez sécuriser comme dans l’exemple ci-dessous :

Exemple d’utilisation

Si vous souhaitez utiliser le captcha seul, il suffit de créer un formulaire avec un unique champ CaptchaType.

L’utilisation de la validation Symfony (c’est à dire l’appel à $form->isValid() dans le contrôleur) va vérifier que la réponse fournie par l’utilisateur est correcte. Le formulaire sera invalide dans le cas contraire.

Le mot de la fin

Vous pouvez maintenant sécuriser vos formulaires sans irriter vos utilisateurs ni reposer sur une quelconque solution tierce avide de collecter des données.

La solution est très évolutive, car il est possible de changer de dictionnaire de mots mais aussi d’ajouter ou de retirer des implémentations de CaptchaInterface afin d’augmenter la diversité des questions proposées.

N’hésitez pas à me faire vos retours dans les commentaires.

Bibliographie

Le test de Turing inversé, le principe derrière les Captchas : https://en.wikipedia.org/wiki/Reverse_Turing_test

Créer des FormType Symfony personnalisés : https://symfony.com/doc/current/form/create_custom_field_type.html

Les services taggués de Symfony : https://symfony.com/doc/current/service_container/tags.html

Créer des thèmes pour les formulaires Symfony : https://symfony.com/doc/current/form/form_themes.html

Le système d’internationalisation de Symfony : https://symfony.com/doc/current/translation.html

Découvrez le travail de la quadrature du net : https://www.laquadrature.net/

Photographie : Rock’n Roll Monkey via Unsplash

Remerciements

Merci à Javier Eguiluz d’avoir mentionné cet article sur le blog de Symfony :
https://symfony.com/blog/a-week-of-symfony-751-17-23-may-2021

--

--