Comment mettre en place un Captcha passif lors de l'envoi d'un formulaire en AJAX
Dernièrement, malgré la mise en place de token csrf, un bot à quand même réussi à spammer l’un de mes formulaires. C’est l’occasion de le renforcer et pour ce faire j’ai choisi d'utiliser un captcha et tant qu'à faire, pour ne pas ennuyer mes visiteurs, un captcha invisible.
Mon choix s’est donc porté sur recaptcha V3 de google. On va passer les commentaires tels que “oui mais c’est google, tu te rends pas compte, tu vends ton âme au diable” ou encore “c’est gratuit c’est toi le produit”, je le sais et ce n’est pas la question. Ce n’est pas la seule solution existante mais elle à le mérite d’être simple d’utilisation et comme on vient de le dire d’être gratuite (jusqu'à 1 million de tests, ce qui devrait suffire).
Récupération des clés publique et privée
Premiere étape enregistrer votre site à cette adresse: https://www.google.com/recaptcha/admin/create?hl=fr
Pensez à bien sélectionner la V3, celà nous permettra d’avoir la vérification invisible. C’est toujours plus agréable pour l’utilisateur final.
Validez
Récupérez les clés qui vont nous servir pour la suite.
Vous pouvez à tout moment les récupérer dans les paramètres de votre site.
Intégration coté front
On ne va pas réinventer la roue, nous allons nous baser sur la doc officielle qui est bien faite et où Google nous propose deux manières de l'implémenter.
Je ne vais donc pas répéter ce que vous dit si bien Google mais je vais vous proposer directement un code custom utilisant un appel ajax. Car sur ce point, la documentation n’est pas très claire.
L’avantage de cette méthode est de ne pas avoir à modifier le contenu du formulaire.
Donc étape importante, ajouter l'API JavaScript en remplaçant “reCAPTCHA_site_key” par la clé publique récupérée plus tôt.
<script src="https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key"></script>
Insérez ensuite votre formulaire html de manière classique.
<form id="contact">
<input type="text" name="message" />
<button>Envoyer</button>
<input type="hidden" id="recaptchaResponse" name="recaptcha_response" value="">
</form>
Il ne reste plus qu'à écrire notre js permettant d’envoyer les informations de notre formulaire et de le nettoyer en cas de réussite.
$(document).on(‘submit’, ‘form#contact’, function(e) {
e.preventDefault();
grecaptcha.ready(function() {
grecaptcha.execute('reCAPTCHA_site_key', {action: 'submit'}).then(function(token) {
// Recuperation du token et insertion dans le champ du formulaire
var recaptchaResponse = document.getElementById('recaptchaResponse');
recaptchaResponse.value = token;
// Recupération des datas du formulaire
var formData = new FormData(document.getElementById('contact'));
// Envoi du formulaire
var xhr = new XMLHttpRequest();
xhr.open('POST', '/ajax/send_form', true);
xhr.onload = function () {
if (xhr.status === 200) {
alert('Votre message à bien été envoyé !');
} else {
alert('Une erreur est survenue. Veuillez éssaiez à nouveau !');
}
};
xhr.send(formData);
});
});
});
Ici aussi, pensez bien à remplacer “reCAPTCHA_site_key” par votre clé publique.
Mais que fait ce code?
Hé bien c’est simple, au moment de l’envoi du formulaire, l’API google va être questionnée concernant l’utilisateur et nous donner un token. Token que nous devons transmettre à notre code PHP pour la vérification. Il sera donc intégré comme champ supplémentaire dans le formulaire.
Intégration serveur
Pour le moment, bot ou humain, il n’y a aucune différence.
Nous devons désormais demander à Google son avis en lui transmettant le token généré côté front.
$captachaResponse = file_get_contents(
"https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $_POST['recaptcha_response'] . "&remoteip=" . $_SERVER['REMOTE_ADDR']
);
// use json_decode to extract json response
$captachaResponse = json_decode($captachaResponse);
if ($captachaResponse->success === false) {
$response["errorMessage"] = "Captcha failed !";
return $this->json($response);
}
// Traitement classique du formulaire...
On oublie pas de remplacer “$secret” par la clé privée.
Ce code va donc questionner l’API et si google juge la requête suspecte, le code renverra un petit message d’erreur sinon il continuera le process.
Notre formulaire est donc parfaitement protégé !
Masquer le badge du captcha
Petit bonus, vous aurez remarqué que l’API fait apparaître un petit badge indiquant la protection captcha.
Certains vont vite avoir le réflexe de le faire disparaître… Voyons ce que nous dit Google à ce sujet.
Vous êtes autorisé à masquer le badge tant que vous incluez le fait que vous utilisez reCAPTCHA Enterprise pour protéger votre site, et que la mention "Les conditions d'utilisation et les règles de confidentialité de Google s'appliquent" soit visible dans le parcours utilisateur.
Nous allons donc intégrer le code suivant afin d’être en règle avec Google.
This site is protected by reCAPTCHA Enterprise and the Google
<a href="https://policies.google.com/privacy">Privacy Policy</a> and
<a href="https://policies.google.com/terms">Terms of Service</a> apply.
Et pour ce qui est de faire disparaître le badge
.grecaptcha-badge {
visibility: hidden;
}
Vous voilà protégé !