Développer un plugin de Captcha pour CaMykS
L'obligation de laisser au visiteur le choix des cookies qu'il accepte ou qu'il refuse, est une vraie plaie, que ce soit pour les visiteurs ou les éditeurs de site internet. Pour les visiteurs, c'est évidemment, cette fenêtre plus ou moins bloquante, qui s'affiche sur tous les sites, et dans laquelle il faut décider des cookies que l'on accepte et ce que l'on refuse.
Pour les éditeurs, ce fut un calvaire, car il a fallut mettre à jour tous les sites pour prendre en charge cette petite fenêtre tout en étant sûrs que l'ensemble des services utilisant des cookies y étaient bien référencés, et surtout en laissant la possibilité au visiteur de les désactiver.
En soit le contrôle des cookies externes est une bonne chose. Il permet de limiter le suivi des visiteurs par des services totalement externes aux sites que l'on visite. Dans les faits, tous les éditeurs ne suivent pas ces directives, et les visiteurs cliquent bien souvent sur "Tout accepter" ou "Tout refuser" sans vraiment savoir ce qu'ils acceptent ou refusent, juste pour ne plus avoir cette fichue fenêtre au dessus de l'information qu'ils recherchent...
Malheureusement, en refusant l'ensemble des cookies, on se bloque souvent l'accès à certains services pourtant utiles à l'information. Il peut s'agir par exemple d'une carte Google Map qui nous indiquerait le lieu à rejoindre et qui ne s'affiche plus. Ou encore, un Captcha qui n'apparait et qui empêche de valider un formulaire de contact ou un commentaire.
Sur skymac.org, nous avons choisit de respecter la loi à la lettre, en vous laissant le choix des cookies que vous souhaitez autoriser ou non sur votre navigateur. Mais nous avons aussi choisit de limiter ces cookies et le traçage par des services externes au maximum, pour cela, nous les avons remplacé, lorsque cela était possible, par des solutions réalisées en interne, et dont on est donc sûr, qu'elles ne contribueront à votre suivi sur Internet.
S'il est difficile de subvenir à une solution de cartographie, ou de streaming vidéo, il est parfaitement possible de créer son propre Captcha.
Nous avons donc remplacé la solution ReCaptcha de Google par un plugin créé pour le CMS que nous utilisons, que nous avons développé pour l'occasion.
Voici un aperçu du processus ce création de ce plugin.
1/ Définition des besoins
Comme d'habitude, la première chose à faire est de définir un cahier des charges, même simple, qui définissent les besoins à remplir lors du développement.
L'objectif du plugin est simple. Il doit pouvoir faire la même chose qu'un autre captcha, à savoir, permettre à un humain de valider un formulaire, tout en bloquant les robots.
Il doit être le plus transparent possible pour le visiteur, et limiter au maximum les faux, tels qu'un visiteur qui serait bloqué comme un robot, ou un robot qui arriverait à poster trop facilement ses spams.
Dans l'idéal, il faudrait qu'il ait les mêmes points d'entrée que les autres plugins Captcha du CMS, afin d'être facilement interchangeable avec ces derniers.
Dernier point, que nous n'avions vu qu'à postériori, il faut pouvoir protéger plusieurs formulaires présents dans la même page. Même si c'est rare, il est tout à fait possible d'avoir plusieurs formulaires simultanément.
2/ Création du plugin
Pour une première version, nous avons cherché une solution simple, qui soit économe en ressources, tant au niveau du serveur que sur le navigateur du visiteur.
L'idée la plus évidente est l'utilisation de Javascript, bien souvent, les robots ne se contentent que de la manipulation de HTML, et n'exécutent pas les scripts Javascript.
Le Captcha doit fonctionner en 2 modes : affichage du Captcha, même s'il est invisible, et vérification du Captcha lors de la validation du formulaire.
Pour commencer il est nécessaire d'indiquer dans quel mode le plugin se trouve, ensuite, et seulement dans le cas de l'affichage, nous n'avons besoin de l'objet qui construit le formulaire.
Le plugin ne nécessite rien de plus que 2 paramètres pour fonctionner. Ensuite, il est parfaitement autonome.
L'accès au plugin est donc assez simple
/**
* Initialise input.
* @param array $params
* @return void
*/
public function initialise($params=array()) {
global $camyks;
/* Build default params */
$dParams = array(
'mode' => 'display',
);
/* Save params */
$this->params = array_merge($dParams, $params);
$this->params['controlInputName'] = 'checkActions';
pour finir la fonction, on ajoute simplement les appels pour l'ajout des scripts côté client en mode affichage
/* Display mode */
if ($this->params['mode'] == 'display') {
if (is_object($this->params['form']) and get_class($this->params['form']) === 'HTMLForm') {
/* Adds scripts */
$this->add_JSFile('GenericCaptcha.js?v=1.0.1');
$this->add_JSLoadScript('GenericCaptcha.initialise("'.$this->params['form']->name.'", "'.$this->params['controlInputName'].'");');
}
}
}
Evidemment, les appels correspondent à des fonctions du CMS qu'il vous faudrait adapter si vous souhaitez créer votre Captcha pour un autre outil.
Ensuite, le plugin ne dispose que d'une autre fonction qui est la vérification du Captcha lors de la validation du formulaire.
/**
* Verify captcha.
* @return boolean result
*/
public function verify() {
if ($this->params['mode'] !== 'verify')
return false;
if (!isset($_REQUEST[$this->params['controlInputName']]))
return false;
if (!((int)$_REQUEST[$this->params['controlInputName']] > 0))
return false;
return true;
}
Ici aussi la fonction est plutôt simple. Elle vérifie d'abord que l'on est bien en mode vérification, ensuite que la valeur est bien retrouvée et qu'elle a été incrémentée par le script côté client.
C'est au final dans le script côté client qu'il y a le plus d'intelligence, et encore que, cela n'a rien de compliqué.
Comme pour les plugins, le script côté client s'articule autour d'un seul objet. Nous trouvons cette manière de faire plus propre et les bugs sont plus faciles à diagnostiquer.
Cet objet dispose de deux fonctions, une première permet sa propre initialisation.
initialise: function(form, controlInputName)
Executée dès que la page est chargée, elle va, dans l'ordre :
- Vérifier que le formulaire indiqué existe vraiment
/* Check form exists */ if (!document.getElementById(form))return;/* Load form as object */ form = document.getElementById(form);
- Créer un champ invisible avec comme nom, la variable donnée
/* Add hidden input in form */ controlInput = document.createElement('input'); controlInput.setAttribute('type', 'hidden'); controlInput.setAttribute('name', controlInputName); controlInput.setAttribute('value', 0); form.appendChild(controlInput);
- Enregistrer le nom du formulaire et de la variable à mettre à jour
/* Save controlInput for form */this.set_param('controlInput', form.name, controlInputName);
- Appliquer un événement "oninput" à tous les textareas du formulaire
/* Add oninput event on each textarea in the form */ textareas = form.getElementsByTagName('textarea'); for (i in textareas) {if (textareas[i].nodeName == 'TEXTAREA')}textareas[i].setAttribute('oninput', this.name+'.update_actionCount(this);'+ (textareas[i].getAttribute('oninput') !== null ? textareas[i].getAttribute('oninput') : ''));
- Appliquer le même événement à tous les champs texte du formulaire
/* Add oninput event on each input in the form */
inputs = form.getElementsByTagName('input');
for (i in inputs)
if (inputs[i].type == 'text')
inputs[i].setAttribute('oninput', this.name + '.update_actionCount(this);'+ (inputs[i].getAttribute('oninput') !== null ? inputs[i].getAttribute('oninput') : ''));
L'événement est simplement un appel à la seconde fonction qui va incrémenter une valeur. Ainsi à chaque fois que le visiteur fait un changement dans l'un des blocs du formulaire, la valeur est mise à jour.
update_actionCount: function(input) {input.form[this.get_param('controlInput', input.form.name)].value ++;},
Ainsi, le simple fait que le champs soit créé par le script, et qu'il soit aussi mis à jour par ce dernier, suffit, pour l'instant, à berner tous les robots qui tentent de polluer les commentaires de spams.
3/ Réflexions finales
Dans son état actuel, le plugin est redoutable, nous avons enregistré un taux de 100% de réussite sur le site de skymac.org, ainsi que tous les autres sites sur lequel il a remplacer ReCaptcha. 100% des commentaires de visiteurs sont passés, tandis que près de 200 messages de robots ont été bloqués, rien que sur ce site, depuis que nous l'avons mis en place.
A la hauteur de nos espérances, le résultat est même meilleur qu'avec ReCaptcha. D'une part, il est moins embêtant pour le visiteur qui n'a rien à faire. D'autres parts, certains bots sont plus malins que d'autres et savent contourner la protection de Google.
Et pourtant, il est bien plus simple techniquement que le ReCaptcha de Google, mais il a l'avantage de n'être présent que sur une dizaine de sites internet. Ainsi, sa confidentialité est sa meilleure arme. Les hackeurs mettront plus de coeur à l'ouvrage lorsqu'il s'agit de casser la protection de millions de sites, plutôt qu'une dizaine.
Et si un jour les robots apprennent à le contourner, il nous suffira de lui offrir une petite mise à jour pour le complexifier, et ainsi lui donner une nouvelle jeunesse.
Petit point amusant, il est si efficace contre les robots que le filtre anti spam réalisé précédemment n'est plus d'aucune utilité, plus aucun message ne lui arrive.
Comme d'habitude, vous pouvez retrouver le code source de ce plugin dans le GitHub du CMS, car il fait désormais partie intégrante de ce dernier.