Le blog de la CT2C

Comment filtrer les robots qui spamment vos formulaires ?

Par Régis Millet aka Kulgar , publié le 21 Décembre 2012

Récemment, je me suis confronté au problème du filtrage des Robots qui spamment les formulaires du site. Il y a de multiples façons de faire, plus ou moins contraignantes, plus ou moins difficiles à mettre en place. Cet article tente de toutes les regrouper pour vous permettre de choisir la meilleure (ou une combinaison des meilleures) solutions et présentera des implémentations simples ou des gems en Ruby On Rails.


Le fond du problème

Commençons par bien voir quel est le réel problème, ou plutôt voyons grosso modo la méthode de fonctionnement de la majorité des spammeurs sur le Web.


Définition de Spammeurs:
J'appelle Spammeurs les robots qui parcourent le Web (et plus particulièrement les sites Web) pour remplir automatiquement les formulaires qu'ils trouvent et ainsi espérer l'affichage de code, de liens, voire de contenus piratés ou qui piratera vos visiteurs.

Que font exactement ces Spammeurs ?

En réalité, ils fonctionnent un peu comme les robots Google. Ils voyagent de site en site, suivent les liens, cliquent partout, etc. jusqu'à trouver dans la page qu'ils chargent un formulaire. C'est simple, ils n'ont qu'à détecter la présence de la balise "<form>" ou même simplement d'un bouton "<submit>".


La majeure partie du temps, dès qu'ils ont trouvé un tel formulaire, ils placent tout un tas d'informations dans chaque champ et les remplissent tous sans distinctions, pour éviter d'oublier des champs éventuellement requis. (Je dis la majeure partie du temps, car certains peuvent être très sophistiqués voire reproduire le comportement humain).


La majeure partie du temps, toujours, il ne leur faut pas plus de quelques secondes (en moyenne 3), pour voyager sur votre site, trouver le formulaire et le valider.


Et encore la majeure partie du temps, comme ils ne font pas de distinctions vis-à-vis des champs, si certains champs doivent être remplis d'une certaine façon (par exemple comme les Captchas), ils ne se cassent pas trop la tête et ils la remplissent comme ils peuvent.



C'est en jouant sur ces différents facteurs qu'il va être possible de distinguer le robot spammeur d'un réel utilisateur.

Commençons par voir la méthode la plus utilisée pour bloquer ces spammeurs: les Captchas utilisant des images.


Les Captchas utilisant des images



Je vous le dis tout de suite, je ne suis pas fan de cette solution. Je ne l'ai jamais mise en place et ne la mettrai certainement jamais en place.


Un bref rappel de ce que sont les Captchas utilisant des images. Ce sont ces petites fenêtres avec du texte déformé souvent illisible (même pour vous) qu'il vous faut écrire dans un champ spécial. Lors de la validation du formulaire, un test est automatiquement effectué pour voir si ce que vous avez écrit correspond bien au texte déformé de l'image.


Pourquoi je n'aime pas cette solution ?

Parce qu'elle est très contraignante. Pas forcément simple à mettre en place, elle est surtout une étape de contrainte pour vos utilisateurs. Il m'arrive souvent de me tromper dans la reproduction du texte qu'il y a dans ce type de Captcha et j'imagine que je suis loin d'être le seul. En général, la présence de ces fenêtres n'incite pas vraiment à continuer ce qu'on souhaitait faire (s'inscrire, enregistrer un commentaire...).


La sécurité est une bonne chose mais il vous faut avant tout garder votre site simple d'utilisation pour vos utilisateurs. Sans quoi vous risquez bien d'en perdre quelques uns dans la démarche. Ce n'est que mon point de vue personnel, mais je sais qu'il est partagé, et de nombreux articles traitant du même sujet cherchent également des solutions alternatives à ce type de Captchas justement pour les contraintes que cette solution représente.


De plus, les robots spammeurs, toujours plus sophistiqués, parviennent de mieux en mieux à passer outre ces Captchas devenues tellement classiques.


Malgré tout, les Captchas utilisant des images représentent une solution retenue par de nombreux sites et ils peuvent arrêter un bon nombre de robots spammeurs. Pour cette solution, je ne saurais trop vous conseiller d'utiliser la gem "simple_captcha"


Simple à mettre en place, elle bénéficie d'une bonne communauté, est régulièrement mise à jour et semble être plutôt robuste face aux robots spammeurs. Il en existe d'autres (kamcaptcha, recaptcha) mais elles semblent moins bien maintenues.


Comme je le disais, le problème majeur de ce type de Captchas, c'est l'inconvénient supplémentaire de lisibilité d'un texte prévu pour être illisible que vous imposez à vos utilisateurs. Aussi une solution alternative s'est très vite développée : les Captcha par questions.


Autre type de Captcha : avec une question cette fois

En réalité, les Captchas sont un ensemble de méthodes utilisées pour différencier un humain d'un robot. Nous avons vu les captchas utilisant du texte déformé et illisible. Il existe un autre type de Captcha, plus intéressante et plus amusante je trouve, celle consistant à répondre à une question simple.


Le principe, de nouveau, est assez simple : il s'agit de poser une question à vos utilisateurs et voir s'ils ont bien répondu. Ce peut être une simple addition, par exemple : combien font 3 + 8 ? Ou une question encore plus simple : "quel est le nom de notre planète ?" Le principe est d'avoir un bon petit nombre de questions toutes faites avec des réponses pré-enregistrées et de vérifier que votre utilisateur a bien répondu.


En général, les robots se font toujours avoir par ce type de piège. Mais l'inconvénient majeur, c'est que certains de vos utilisateurs répondront à côté de la plaque, parfois même juste par étourderie. Dans ce cas, ce n'est pas grave, vous les renvoyez vers le formulaire pré-rempli avec leurs infos et posez une autre question.


Je trouve cette solution plus élégante que les Captchas avec du texte déformé, et surtout beaucoup moins contraignante pour les utilisateurs. Pour cette solution, je ne vous présenterai pas de code, ce n'est pas quelque chose de très complexe à mettre en place. Par contre, je vous conseille tout de même une Gem : humanizer. Je ne l'ai pas utilisée mais elle semble simple à mettre en place, et surtout les questions utilisées par la Gem sont déjà traduites dans de nombreuses langues, y compris le français !


Malgré l'élégance de cette solution, on regrettera toujours la présence d'un champ de formulaire supplémentaire à remplir.


Troisième type de Captchas, les captchas ludiques!

Proposée en commentaire de cet article, cette solution me semble devoir retenir toute notre attention. En effet, les captchas classiques ont pour inconvénient majeur d'être illisibles et d'être de plus en plus contournées par les robots toujours plus performants. Alors cette société: are you a humana eu la riche idée de proposer des mini-jeux que seul un humain peut résoudre.


L'idée est excellente ! Les jeux sont bien conçus et tout a été prévu : de base ils sont affichés en HTML5. Mais si le navigateur de votre utilisateur est trop ancien, le plugin le détecte automatiquement et remplace le jeu en HTML5 par une version Flash. Il existe en version mobile, et est totalement gratuit pour une utilisation basique.


Par contre dès qu'il s'agira de le personnaliser, il faudra malheureusement débourser de l'argent. Notamment pour avoir accès à une version traduite en français, de base il est en anglais ou pour pouvoir choisir les jeux affichés dans le Captcha.


Mais ne faisons pas trop la fine bouche! La version gratuite est tout de même très fournie et vous évitera sûrement 99,99% des spammers classiques + ne fera pas fuir vos utilisateurs. S'il y a une solution Captcha à retenir, c'est celle-ci !


Voyons une autre méthode, les reverse Captchas !


Reverse Captchas

En fait, le principe des reverse Captchas est beaucoup plus simple que celui des Captchas (on se demande pourquoi on n'y a pas pensé avant). Comme je le disais en introduction, les robots ont une fâcheuse tendance à vouloir remplir tous les champs de votre formulaire, peu importe s'ils sont sensés être remplis ou non.


Il s'agit d'ajouter au formulaire un ou plusieurs champs qui ne pourront être remplis que par un robot et ne seront jamais remplis par des humains. Le plus simple est le principe du "honeypot" ou "pot de miel" : un champ invisible pour les utilisateurs mais bel et bien présent dans le formulaire qui, s'il est rempli, empêchera la validation du formulaire.



Voici une implémentation simple en Ruby On Rails.

Admettons que vous voulez protéger votre formulaire de commentaires du blog de votre site. Vous avez donc le model "Comment". Modifiez-le comme ceci :



class Comment < ActiveRecord::Base
attr_accessible :author, :content
attr_accessor :auto_check
end

J'ai simplement ajouté un attribut non persistant (i.e. qui ne sera pas enregistré dans la base de données), nommé "auto_check" à l'aide de "attr_accessor". C'est cet attribut que nous utiliserons pour tester automatiquement si l'auteur du message est un spammer ou non. S'il est rempli nous déduirons qu'il s'agissait d'un spammer.


Vous pouvez tout à fait opter pour un attribut persistant, dans ce cas n'oubliez pas d'effectuer la migration adéquate. Cela vous permettrait, par exemple, d'enregistrer tout de même les commentaires dont ce champ est rempli, puis de ne récupérer que ceux dont le champ "auto_check" est vide. Côté administration de votre site, cela vous permettrait ainsi de récupérer les "faux positifs" (d'éventuels utilisateurs qui seraient parvenus à remplir ce champ malgré eux).


Ensuite, dans votre controller, et avant d'enregistrer le commentaire, testez si ce champ est rempli ou non, comme ceci :



  def create
# on récupère l'article et on construit le commentaire de façon classique
@article = Article.find(params[:article_id])
@comment = @article.comments.build(params[:comment])

respond_to do |format|
# on effectue l'opération de filtrage
if @comment.auto_check.blank?
# Si le champ "pot de miel" est vide, on effectue les tâches normales
if @comment.save
format.html { redirect_to article_path(@article), :notice => "Commentaire enregistré" }
else
flash.now[:alert] = "Echec de l'enregistrement du commentaire"
format.html { render :show }
end
else
# Si le champ "pot de miel" n'est pas vide, on ne sauvegarde pas le commentaire
format.html { redirect_to article_path(@article), :notice => "Commentaire enregistré" }
end
end

Notez que si le champ "auto_check" n'est pas vide, j'effectue tout de même une redirection avec un message Flash signalant que le commentaire a été enregistré. Hé oui, car il arrive très fréquemment que des robots parviennent à détecter la présence d'une alerte dans la page renvoyée par le site, et tenteront de changer leur attitude dans ce cas avant de remplir de nouveau le formulaire. Mais bon, je vous rassure, la plupart du temps, ça n'a pas vraiment d'importance. :)


Enfin, dans la vue, faites que votre champ soit invisible pour vos utilisateurs :



<%= form_for @comment do |f| %>
<%= f.text_field :author %>
<%= f.text_field :content %>
<%= f.text_field :honeypot, :class => "hidden" %>
<% end %>

Et dans votre css:


.hidden{
display:none;
//ou bien
position: absolute;
left: -9000px; // Mais dans ce cas les aveugles accéderont tout de même à ce champ... alors n'oubliez pas de leur mettre un avertissement "ne pas remplir"
}

Évidemment, adaptez votre code selon vos besoins. Dans le code ci-dessus, les faux positifs seront tout bonnement ignorés.


Enfin, si vous ne souhaitez pas trop vous embêter avec l'implémentation, plusieurs Gem existent et mettent en place le même principe. La meilleure actuellement est negative captcha.


Pour moi, cette solution est une des top solutions. L'inconvénient, évidemment, c'est qu'un spammeur non-robot pourra facilement passer outre. Mais existe-t-il réellement des solutions simples pour filtrer des spammeurs non-robot ? Je ne crois pas. Les reverse captchas possèdent un beau panel d'avantages : invisibles pour vos utilisateurs, elles ne représentent aucun inconvénient et sont extrêmement simples à mettre en place.


Passons à une autre solution toute aussi ingénieuse que les Reverse Captcha.



Filtrage en considérant le temps pour poster un formulaire

Comme je le disais en introduction, il ne faut en général pas plus de quelques secondes pour un robot pour trouver votre formulaire sur votre site et poster un spam. Nous pouvons utiliser cela à notre avantage pour filtrer ces robots, simplement en étudiant le temps qu'il a fallu à votre visiteur pour accéder à votre site et valider son commentaire.


C'est une solution utilisée dans Wordpress. Ce que nous allons mettre en place en ruby on rails sera une version simplifiée que j'ai découverte sur un blog d'un confrère anglais mais qui suffit amplement (voir les sources à la fin de l'article).


Dans votre fichier "application_controller.rb", ajoutez un before_filter comme ceci :



before_filter :spammer_timestamp

def spammer_timestamp
# On enregistre dans la session de navigation de l'utilisateur un Timestamp, ou on le récupère s'il existe déjà
session["spammer_timestamp"] ||= Time.now
end

Ensuite, lors de la validation de votre formulaire, il ne vous reste plus qu'à tester si le temps écoulé est bien supérieur à quelques secondes. Disons qu'un humain devrait mettre au moins 20 secondes entre le moment où il accède à votre site et le moment où il valide son formulaire. (Et encore, cet humain serait fichtrement rapide !). Reprenons notre méthode "create" de tout à l 'heure :



def create
# on récupère l'article et on construit le commentaire de façon classique
@article = Article.find(params[:article_id])
@comment = @article.comments.build(params[:comment])

is_spammer = false

elapsed_time_before_commenting = Time.now - session["spammer_timestamp"] if elapsed_time_before_commenting < 20 # 20 secondes
logger.warn("Spammer détecté")
is_spammer = true
end

respond_to do |format|
# on effectue l'opération de filtrage
if !is_spammer
# S'il ne s'agit pas d'un spammer, on enregistre le commentaire
if @comment.save
format.html { redirect_to article_path(@article), :notice => "Commentaire enregistré" }
else
flash.now[:alert] = "Echec de l'enregistrement du commentaire"
format.html { render :show }
end
else
# S'il s'agit d'un spammer, on ignore le commentaire comme tout à l'heure
format.html { redirect_to article_path(@article), :notice => "Commentaire enregistré" }
end
end

Et voilà ! Cette technique est aussi bonne que celle du reverse captcha voire peut-être meilleure, mais sans aucun doute plus simple à contourner par un robot.

Si vous avez peur des faux positifs, vous pouvez toujours faire apparaître le bouton "valider" du formulaire au bout de 20 secondes à l'aide de Javascript, cela évitera sûrement des désagréments pour certains utilisateurs ultra rapides. Mais en principe, il faut bien plus de 20 secondes pour poster un commentaire.


Sachez qu'il existe des solutions plus complexes et plus robustes, comme ce tutoriel utilisant JQuery et un système de cookie. Le tutoriel a été initialement conçu pour PHP mais il est facilement adaptable en Ruby On Rails. L’inconvénient, c'est que la méthode présentée dans ce tutoriel ne fonctionne pas si l'utilisateur n'accepte pas les cookies ou s'il a désactivé Javascript. Un tel utilisateur ne pourrait alors pas poster de commentaires. Rien n'est parfait !

Enfin, dernière technique couramment utilisée que je connaisse, c'est le système de score.


Filtrage par mauvais score

Cette méthode est très bien connue et maîtrisée puisque c'est celle majoritairement utilisée pour filtrer les spams dans les mails. Il s'agit d'effectuer une série de tests simples qui donneront un score au contenu de votre commentaire puis de décider, selon ce score, ce que vous en faites.


Cette méthode, quoique lourde, mérite toute votre attention car c'est l'une des rares méthodes qui va permettre de filtrer, non seulement les Spams issus de robots, mais également ceux entrés manuellement par un utilisateur !


Le principe est simple, il s'agit d'effectuer une série de test, selon des règles préconçues, qui octroieront ou déduiront des points au commentaire. Vous faites la somme de tous ces points et obtenez un total. Vous filtrez ensuite les commentaires dont le total serait inférieur à une certaine barre.


Je me base sur l'article d'un confrère anglais, dont les règles semblent être très bien faites (je mettrai mes sources à la fin de cet article). Je n'expliciterai par contre pas le code Ruby On Rails pour chaque règle, ce serait beaucoup trop lourd pour le présent article. Si vous le souhaitez, je pourrais en faire un billet à part. Voici donc ces règles :


  • Combien de liens le contenu du commentaire possède-t-il ? -1 point par lien s'il y a plus de 2 liens dans le commentaire. +2 points s'il y a moins de 2 liens.
  • Quelle est la taille du contenu du commentaire ? Plus de 20 caractères sans compter les liens : +2points. -1point dans le cas contraire
  • Nombre de commentaires déjà postés par la même personne (en se basant sur son email, par exemple) ? +1point par commentaire précédemment approuvé. -1 point par commentaire précédemment signalé comme spam
  • Recherche par mots clés couramment présents dans les spams (viagra, casino, etc.) : -1point par mot clé trouvé
  • Recherche par mots clés ou caractères suspicieux dans les urls du message (? & % .html...) : -1point par mot clé trouvé
  • URL qui ont certain nom de domaine (.pl, .cn, les domaines généralement utilisés pour des sites pirates...) : -1 point par url
  • La taille des URL : -1 point pour toute URL dépassant 30 caractères
  • Le premier mot du contenu (Interesting, sorry, nice, cool et les équivalents français, les spams commencent généralement par ce type de mot) -10 points
  • Le nom de l'auteur du commentaire possède un "http://" -2 points si c'est le cas
  • Le corps du message se retrouve en tout ou en partie dans un précédent commentaire : -1point si c'est le cas, -10 points si le précédent commentaire est signalé comme un spam
  • Recherche de caractères aléatoires, comme une suite de 5 consonnes, -1point par suite trouvée

C'est un ensemble de règles qui vous permettront d'avoir un bon score final, évidemment si c'est sous la barre de 0, ce peut être facilement considéré comme un spam, et dans le cas contraire, vous pouvez le laisser s'afficher en toute tranquillité.


Sachez qu'il existe des services tiers qui vous offrent exactement ce type de filtrage pour n'importe lequel de vos formulaires, notamment Akismet qui est facilement intégrable dans vos applications Rails grâce à la gem rakismet. Toutefois ce type de services présentent de nombreux désavantages : ajout d'une latence le temps de la validation du commentaire, votre commentaire passe dans un service externe au vôtre, c'est payant pour une utilisation pro, et en plus, ce n'est pas invisible pour vos utilisateurs... Bref, que du moins !


Conclusion et sources


Voilà grosso modo l'ensemble des techniques que j'ai trouvées pour filtrer les Spams au niveau des formulaires. Mes deux favorites restent le Reverse Captcha et le filtrage basé sur un timestamp. Évidemment, la plus solide de toutes restera encore et toujours une validation manuelle des commentaires ! Mais pour d'autres formulaires, comme un formulaire de contact, ce peut être de très bonnes et robustes solutions. Chaque solution a ses avantages et inconvénients, à vous de voir ce que vous préférez.


Si vous connaissez d'autres techniques pour filtrer les Spams sur les sites, peu importe le langage, n'hésitez pas à partager en commentaire, je tâcherai de les intégrer dans l'article. Merci de m'avoir lu et à bientôt !


Voici mes sources :Simple Detection of Comment Spam in Rails
How I built an effective blog comment spam blocker
Rails - Choosing captcha plugin
Tutorials: Safer Contact Forms


Index -- --

  • 5 Commentaire


  • J'utilise une protection par mot de passe (que je fournis) pour le répertoire qui contient le formulaire. Et c'est très simple!


    Par jp_swing, le 12 Janvier 2015

  • Les robots ont cassé la plupart des systèmes de captcha, y compris les questions de type "êtes vous humain". Ils utilisent google pour répondre de manière heuristique aux questions simples (ex: "quelle est la couleur du ciel?"), et des bases de données payantes mises à jour quotidiennement pour les questions un peu plus aléatoires.
    Si votre site est un minimum populaire (en gros dans le top 1'000'000 alexa), captcha ou questions n'arrêteront pas les bots.

    Une solution qui marche pour le moment est d'intégrer akismet et stopforumspam.

    Source: experience personnelle, après avoir galéré pendant 1 an. Mon retour d'expérience ici: http://wololo.net/2012/12/06/the-battle-against-spammers/


    Par wololo, le 13 Janvier 2013

  • @Maelig : Je ne connaissais pas ces Captcha, effectivement ils sont une très chouette alternative aux Captchas avec texte déformé, je les ajouterai à l'article ! Merci ^^

    @Chris Tophe : WordPress utilise quelque chose de plus poussé, c'est en libre téléchargement ici : http://wordpress.org/extend/plugins/cookies-for-comments/
    Le principe de base de leur plugin repose sur le fait qu'un Bot ne prend en compte ni les images ni les feuilles de style. Ils associent un cookie spécial à une image spécifique qui, si elle est téléchargée, enverra également le cookie. Puis ils vérifient la présence de ce cookie. La vérification du temps est une sorte de "bonus" dans leur plugin, une double vérification quoi. ^^


    Par Kulgar, le 23 Décembre 2012
  • Voir tous les commentaires
    2 de plus
Insérez votre commentaire
  1. Min: 50 caractères, Max: 800. Actuellement: 0 caractères

  2. ne pas remplir