Créer un captcha en PHP

Septembre 2012

Les sites web sont visités et utilisés non seulement par des êtres humains (ça c'est pas un scoop), mais aussi par des machines, des ordinateurs.

On appelle ces programmes qui parcourent sans cesse le web des robots (on dit aussi bot).

Certains bots ont de bonnes intentions, comme par exemple les robots d'indexation des moteurs de recherche (appelés crawler) comme Googlebot (Google), ou Slurp (Yahoo !).

Mais d'autres bots ont des objectifs beaucoup moins louables, leur but est par exemple de s'inscrire sur des forums de discussion pour poster des messages publicitaires (spam), ou de poster des commentaires de spam sur un blog.

Qu'est-ce qu'un captcha ?

Il existe plusieurs solutions pour lutter contre ces robots spammeurs, l'une d'entre elle consiste à soumettre l'utilisateur à un test auquel seul un être humain est sensé être capable de répondre (on appelle ça un test de Turing).

En pratique, ça se fait tout simplement en ajoutant un champ antispam appelé Captcha dans un formulaire HTML qu'on souhaite protéger contre les robots.

Il existe plusieurs types de Captcha :

  • Texte déformé (ex: reCaptcha, captcha php avec GD)
    Le fonctionnement est très simple : on présente à l'utilisateur une image qui contient un texte déformé ou brouillé, et pour passer le test avec succès il faut que l'utilisateur saisisse le texte qu'il voit dans un champ texte.
    Ce type de captcha est le plus répandu, cependant il commence à montrer ses limites car les robots sont de plus en plus élaborés et arrivent à lire ces images tout comme le font les humains. Du coup on est obligé d'utiliser des captchas de plus en plus déformés, si bien qu'ils en deviennent difficiles à déchiffrer pour les êtres humains !

    Recaptcha
  • Question / Réponse
    Le principe est très similaire au texte déformé : on pose une question très simple à l'utilisateur, du style "Combien font deux plus vingt ?", et il faut écrire le résultat (la réponse) dans un champ texte.
    Les captcha Q/R sont de plus en plus utilisés car ils sont beaucoup plus efficaces pour stopper les robots, beaucoup moins frustrants pour l'utilisateur car ils ne nécessitent pas d'effort, contrairement à la lecture d'une image déformée, et aussi très facile à mettre en place techniquement.
  • Actions simples à effectuer (ex : glissière sur pacitel, clic sur des images : chat, voiture, moto...)
    Encore assez rare pour le moment, on commence à voir certains sites qui utilisent des sortes de tests de logique très simple.
    Par exemple, on présente une série de 9 photos à l'utilisateur (représentants divers objets : une voiture, un chat, une moto, le ciel, une ville...), et on demande à l'utilisateur de cliquer sur un animal.
    Autre exemple, encore plus simple : on créé un bouton on/off (avec une petite glissière toggle comme sur iPhone, en javascript), par défaut positionné sur Off, et on demande à l'utilisateur de le glisser sur On.

    Captcha glissière jQuery pacitel

Aussi bizarre que ça puisse paraître, les robots, aussi élaborés soient-ils, peuvent paradoxalement être arrêtés par des tests aussi simple que "Combien font deux plus vingt ?" (surtout lorsque la question est posée dans une autre langue que l'anglais).

Comment créer un captcha en PHP ?

Pour mettre en place un système de captcha sur votre site avec PHP, il y a 2 solutions :

  • Gérer soi-même le captcha de A à Z
  • Utiliser un service de captcha comme reCaptcha

Créer un système de captcha

Si vous décidez de coder vous même votre propre système de Captcha, c'est ici que ça se passe.

Quelque soit le type de captcha que vous voulez créer (image, question/réponse), vous devrez utiliser la session.

En effet, lorsque le serveur va générer le test (l'image ou la question), lors de l'affichage du formulaire, il va devoir garder en mémoire la question posée à chaque utilisateur, qui lui permettra de vérifier lors du submit du formulaire que ce que l'utilisateur a répondu est bien la réponse attendue.

Et pour faire ça (affecter des données différentes à chaque utilisateur), le mieux c'est d'utiliser les sessions de PHP, via la variable superglobale $_SESSION.

Pour cet exemple, on va créer un captcha de type question/réponse, qui est plus simple à comprendre. Si vous souhaitez utiliser un captcha image, vous pouvez utiliser l'extension PHP GD pour générer l'image de votre captcha, et la déformer...

Affichage du formulaire

L'affichage du formulaire est très simple. On va d'abord stocker la liste de nos questions/réponses dans un tableau $liste_questions, et ensuite on va en choisir une au hasard, celle qui sera posée à l'utilisateur (et on stocke l'identifiant de la question posée dans la session au passage, pour pouvoir vérifier la réponse lors du traitement du formulaire).

<?php
# Liste des questions avec leurs différentes réponses possibles
$liste_questions = array(
	'question1' => array(
		'question' => "Quelle est la couleur du cheval blanc ?",
		'reponses' => array('blanc', 'blanche', 'neige', 'clair')
	),
	'question2' => array(
		'question' => "Combien font deux + quatre ?",
		'reponses' => array('6', 'six')
	)
);

# Activation des sessions (pour que PHP charge la session de l'utilisateur, via le cookie PHPSESSID)
# à placer impérativement avant tout affichage, car cette fonction a besoin d'envoyer des headers HTTP
session_start();

# Sélection d'une question à poser au hasard
$id_question_posee = array_rand($liste_question);

# Mémorisation de la question posée à l'utilisateur dans la session
$_SESSION['captcha']['id_question_posee'] = $id_question_posee;

# Affichage du formulaire HTML
?>
<form action="" method="post">
	<h3>Captcha</h3>
	Question : <?php echo $liste_questions[$id_question_posee]['question']); ?>
	Réponse  : <input type="text" name="captcha_reponse" value="" />

	<input type="submit" value="Envoyer le formulaire" />
</form>

Traitement du formulaire

<?php
# Liste des questions avec leurs différentes réponses possibles
$liste_questions = array(
	'question1' => array(
		'question' => "Quelle est la couleur du cheval blanc ?",
		'reponses' => array('blanc', 'blanche', 'neige', 'clair')
	),
	'question2' => array(
		'question' => "Combien font deux + quatre ?",
		'reponses' => array('6', 'six')
	)
);

# Activation des sessions (pour que PHP charge la session de l'utilisateur, via le cookie PHPSESSID)
# à placer impérativement avant tout affichage, car cette fonction a besoin d'envoyer des headers HTTP
session_start();

# On récupère l'identifiant (clé) de la question posée dans la session
$id_question_posee = $_SESSION['captcha']['id_question_posee'];

# On récupère la réponse de l'utlisateur
$reponse_utilisateur = $_POST['captcha_reponse'];

# Vérification de la réponse : si la réponse de l'utilisateur n'est pas dans la liste des réponses exactes, on affiche un message d'erreur
if( !in_array($reponse_utilisateur, $liste_questions[$id_question_posee]['reponses']) ){
	echo "Vous avez répondu $reponse_utilisateur à la question captcha, ce n'est pas une bonne réponse. Traitement annulé";
	die();
}
?>

Utiliser reCaptcha en PHP

reCaptcha est un service gratuit proposé par Google pour intégrer facilement un captcha sur un site.

Le fonctionnement est très simple :

  1. Lors de l'affichage du formulaire à protéger, votre serveur demande un captcha à reCaptcha.
    Celui-ci lui donne en retour un identifiant unique (qu'on appelle le jeton).
  2. Vous affichez le captcha que vous a fourni recaptcha, et l'utilisateur va entrer la réponse dans le champ, puis poster le formulaire (l'envoyer au serveur)
  3. Le serveur va vérifier que l'utilisateur a entré la bonne réponse en demandant à reCaptcha, à l'aide du jeton que celui-ci nous a fourni à l'étape 1.
    Et voilà, si la réponse est mauvaise, il vous suffit de ne pas traiter le formulaire et d'afficher un message d'erreur pour informer l'utilisateur de la raison pour laquelle son formulaire a été refusé.

Pourquoi utiliser reCaptcha ?

Ce système a grosso modo 3 avantages :

  • Il est simple à mettre en oeuvre techniquement
  • Les reCaptcha sont assez faciles à lire puisque les lettres ne sont pas tirées au hasard pour former un mot de passe incompréhensible, elles sont choisies pour former des syllabes, beaucoup plus facile à lire, on peut même deviner une lettre qu'on a du mal à déchiffrer en devinant le son de la syllabe, c'est plus intuitif.
  • Il a une double utilité puisqu'en plus de test de turing, il aide Google à numériser les livres en lui offrant une main-d'oeuvre gratuite (les utilisateurs qui remplissent les formulaires), car les reCaptcha sont composés de 2 mots : l'un fait office de test, et l'autre sert d'OCR à Google.
    Ce dernier point n'est pas forcément en avantage, à vous de juger.

Installer reCaptcha

Première étape : rendez-vous sur le site officiel et inscrivez-vous (si vous avez déjà un compte Google vous pouvez l'utiliser, car reCaptcha a été racheté par Google il y a quelques années).

Après votre inscription, vous vous verrez attribué une clé publique et une clé privée. Vous pourrez également télécharger l'API PHP, qui se présente sous la forme d'un script PHP : recaptchalib.php.

Ensuite ouvrez le script PHP qui affiche votre formulaire, incluez recaptchalib.php (en lui indiquant vos clés publique et privée), et affichez le captcha en appelant la fonction recaptcha_get_html :

<?php
// Inclusion de l'API reCaptcha
require 'recaptchalib.php';

// Définition des 2 clés
$cle_publique = "LoremIpsum";
$cle_privee   = "DolorSitAmet";

// Affichage du bloc reCaptcha dansle formulaire
echo recaptcha_get_html($cle_publique);
?>

C'est tout, il n'y a que ça a faire en ce qui concerne l'affichage du champ recapcha dans votre formulaire (bien sur vous pouvez l'afficher où vous voulez dans votre page, il faut juste faure le echo à l'endroit qui vous intéresse dans le code html).

Si vous voulez en savoir plus c'est par ici : programmer sur excel avec les macro vba.

Maintenant, allez au niveau du code PHP qui traite ce formulaire.

<?php
// Inclusion de l'API recaptcha
require 'recaptchalib.php';

// Définition des 2 clés
$cle_publique = "LoremIpsum";
$cle_privee   = "DolorSitAmet";

// Interrogation du serveur reCaptcha
// La réponse de reCaptcha est stockée dans la variable $reponse
$reponse = recaptcha_check_answer(
	$cle_privee,						// Votre clé privée
	$_SERVER['REMOTE_ADDR'],			// L'adresse IP de l'utilisateur
	$_POST['recaptcha_challenge_field'],// Un identifiant (jeton) permettant à reCaptcha de vérifier la réponse
	$_POST['recaptcha_response_field']	// Ce que l'utlisateur a saisi dans le champ texte du captcha
);

if( !$reponse->is_valid ){
	echo "Vous avez échoué au test captcha, impossible de traiter votre formulaire";
	die();
}
?>

Et voilà, votre formulaire est protégé contre le spam.

Si vous utilisez un CMS comme Wordpress, il existe des plugins qui permettent d'utiliser recaptcha sans mettre les mains dans le cambouis.

Quelles sont les alternatives au captcha ?

Il existe d'autres méthodes que de tester l'utilisateur avec un captcha pour lutter contre le spam.

L'intérêt c'est bien évidemment de ne pas frustrer les internautes, car en général les gens n'aiment pas résoudre un captcha, c'est une contrainte qui peut conduire certains visiteurs à l'abandon (ils ne remplissent pas le formulaire, et renoncent ainsi à poster un commentaire ou à s'inscrire sur votre forum). Dans le jargon on dit que ça diminue le taux de conversion (conversion rate en anglais).

On peut par exemple soumettre un contenu à un service centralisé qui est utilisé par des milliers de sites et qui permet d'estimer si oui ou non il s'agit de spam.

Le plus célèbre de ces services est sans doute Akismet, qui est la protection contre le spam utilisée par le moteur de blog Wordpress.

Il y a aussi le site Stop Forum Spam qui propose une API permettant de déceler les inscriptions de robots spammeurs sur des forums (comme phpBB).

À côté de ces API, on peut aussi essayer de piéger les robots à leur propore jeu, en leur trouvant des différences par rapport aux inscriptions "normales".

Une technique assez simple consiste à mettre plein de champs cachés inutiles dans le formulaire (type=hidden ou alors mieux : champ masqué en CSS).

Si un utilisateur humain remplit ce formulaire, ces champs cachés seront vides.

Mais les robots eux vont remplir ces champs, ils sont beaucoup trop stupides pour avoir un raisonnement et laisser ces champs vides, donc on les piège, comme on judo on utilise leur force contre eux ^^.

Découvrez ce tutoriel photoshop : texte en diamants bling bling à lire tout de suite !

8 commentaires :
commentaire n°2640 par totototo
totototo samedi 7 septembre 2013, 15:57
Merci c'est cool
commentaire n°2802 par fiches pratiques
fiches pratiques vendredi 18 avril 2014, 22:33
Oui les robpts sont parfois stupides mais avec le temps ils apprennent et jouent le jeu c comme la serrure et la clé. L'important dans tout ça c'est le controle humain..
commentaire n°3191 par James
James mardi 24 novembre 2015, 08:23
google
commentaire n°3192 par Harry
Harry mardi 24 novembre 2015, 09:53
I read your post and very interesting post and informative post. I am very glad to see this informational post. Get rubber home gym flooring from Gymflooringco.co.uk
commentaire n°4224 par angek8607
angek8607 lundi 1 juillet 2019, 23:42
je ne suis pas satisfaite alors la pas du tout!!!!!!!!!.
commentaire n°4488 par RightTon Blazer
RightTon Blazer dimanche 29 septembre 2019, 19:08
Merci beaucoup !
commentaire n°4584 par Antibuff
Antibuff mercredi 27 novembre 2019, 15:10
J'ai jamais vu un code avec autant de faute (erreur)

Une parenthèse par ci, une variable inconnu. Pas mal de petites choses qui ne se voit pas directement.
commentaire n°4982 par Guillaume
Guillaume mardi 28 avril 2020, 09:46
Merci pour ce tuto
Dans le premier exemple, attention, la variable $liste_question est écrite une fois avec un "s", une fois sans...

Et il y a une parenthèse en trop à la fin de :
    Question : <?php echo $liste_questions[$id_question_posee]['question']); ?>
facultatif
Facebook Twitter RSS Email
Forum Excel
Venez découvrir le nouveau forum excel question/réponse à la stackoverflow.com !
Forum Excel
hit parade n'en a rien a foutre du W3C Positionnement et Statistiques Gratuites Vincent Paré