Développer une nouvelle fonctionnalité pour Honeypot

Honeypot c'est bien, ça permet de pièger des spam-bots.

Bon, c'est un bon constat de départ.

Ce module ajoute une bonne protection aux formulaires présents sur votre site, tout en évitant les CAPTCHAs qui bloquent tout autant certains humains (et leur font de la peine) que certains spam-bots.

Ce module va offrir une bonne protection, et va permettre de récupérer les IP de ces spam-bots pour pouvoir les bannir ensuite par le blocage d'IPs fourni par Drupal.

Mais les informaticiens sont fainéants. C'est bien connu. Certaines sont même tellement fainéantes, que quand elles croient au père noël, elles lui demandent un module custom...

Bon. J'avais envie de préserver la magie, et je me suis fait passer pour le Père Noël sur ce coup là, bien que ne connaissant pas le module Honeypot (mais avec un nom pareil, je me doutais bien de ce qu'il faisait).

Après l'avoir installé, on peut remarquer qu'il y a une api, magnifique ! Et surtout, Honeypot fournit un hook appelé lorsqu'il lève un cyber-lièvre.


/**
 * React to the rejection of a form submission.
 *
 * When honeypot rejects a form submission, it calls this hook with the form ID,
 * the user ID (0 if anonymous) of the user that was disallowed from submitting
 * the form, and the reason (type) for the rejection of the form submission.
 *
 * @param (string) $form_id
 *   Form ID of the form the user was disallowed from submitting.
 * @param (int) $uid
 *   0 for anonymous users, otherwise the user ID of the user.
 * @param (string) $type
 *   String indicating the reason the submission was blocked. Allowed values:
 *     - honeypot: If honeypot field was filled in.
 *     - honeypot_time: If form was completed before the configured time limit.
 */
function hook_honeypot_reject($form_id, $uid, $type) {
  if ($form_id == 'mymodule_form') {
    // Do something...
  }
}

Nous avons donc le hook qui se déclenche au bon moment et dans le bon contexte. Il faut donc maintenant bannir l'IP du spam-bot. Tout comme Drupal l'aurait fait lorsqu'une IP lui est passée dans la gestion du module Blocked IP.


Et en effet on trouve la fonction recherchée dans modules/system/system.module :

function system_block_ip_action() {
$ip = ip_address();
db_insert('blocked_ips')->fields(array('ip' => $ip))->execute();
watchdog('action', 'Banned IP address %ip', array('%ip' => $ip));
}

Rien de bien méchant, la fonction system_block_ip_action récupère l'ip du visiteur, l'ajoute dans la table blocked_ips qui liste les adresses ip à bloquer, puis ajoute une entrée dans le livre de bord de Drupal.

Nous avons le hook déclencheur, puis nous avons la fonction à appeler. Il suffit donc de créer un module qui implémentera le hook_honeypot_reject() pour appeler system_block_ip_action. Je passe sur le fichier .info qui est très classique et ne sert qu'à définir le nom, ranger ce module dans la catégorie spam prevention et à appeler le code du module, que voici :

/**
* Implements hook_honeypot_reject($form_id, $uid, $type)
*
* @param (string) $form_id
* Form ID of the form the user was disallowed from submitting.
* @param (int) $uid
* 0 for anonymous users, otherwise the user ID of the user.
* @param (string) $type
* String indicating the reason the submission was blocked. Allowed values:
* - honeypot: If honeypot field was filled in.
* - honeypot_time: If form was completed before the configured time limit.
*/
function hive_honeypot_reject($form_id, $uid, $type) {
  // if a spambot is detected by the Honeypot module, we call the system_block_ip_action() to automatically ban the spambot IP.
  system_block_ip_action();
}

Le module a été déployé aujourd'hui et a banni ses premiers spams bots. Dans l'idéal, il faudrait également pouvoir gérer un banissement des adresses IP par listing dans le .htaccess pour permettre l'utilisation du module dans le cas de gros sites sans perdre en performances.

De la même façon, une ligne dans l'interface d'administration Drupal permettant d'automatiser ou non le banissement de l'IP serait un plus appréciable... Mais ça sera pour plus tard !

Pièces jointes: