AccueilFAQStatistiquesDiversContact

Anti-spam : comment protéger son blog/forum des spams de commentaires

De nombreux webmasters ne souhaitent pas protéger leurs blogs ou forums avec des CAPTCHA ou services de filtrage divers afin de ne pas pénaliser leurs visiteurs. Cependant, il est toujours possible de se protéger des spams de commentaires avec quelques astuces très simples utilisées pour faire la différence entre un robot et un humain, mais aussi de pousser les éventuels spammeurs à se piéger eux-mêmes en les renvoyant sans peine sur un formulaire spécifiquement conçu pour les blacklister ou les renvoyer ailleurs, et bien entendu, en toute transparence pour les visiteurs.

I - Blogs

II - Forums


I - Blogs :

  • Multiples fichiers JS externes :
  • Très simple à installer et relativement efficace : le formulaire se trouve découpé en plusieurs parties JavaScript, chacune d'elle dans une fichier externe faisant référence à l'un ou plusieurs des autres fichiers :

    form_01.js :

       function nom_form(){
          document.write("Votre nom: <input type=text name=nom size=20><p>");
       }
       function close_form(){
          document.write("</form>");
       }
       var monscript='mon_scrip.pl';
    
    form_02.js :
       function commentaire_form(){
          document.write("Votre commentaire:<br><textarea name=commentaire cols=48 rows=6>");
          document.write("</textarea><p>");
       }
    
    form_03.js :
       function affiche(){
          document.write("<form method=post action="+monscript+">");
          nom_form();
          document.write("Votre email: <input type=text name=email size=20><p>");
          commentaire_form();
          document.write("<input type=submit value='Poster le message'>")
          close_form();
        }
    
    Page HTML :
       <html>
       <head>
       <script language="JavaScript" src="form_01.js" type="text/javascript"></script>
       <script language="JavaScript" src="form_02.js" type="text/javascript"></script>
       <script language="JavaScript" src="form_03.js" type="text/javascript"></script>
       </head>
       <body>
       ...
       ...
       <script>affiche();</script>
    
    

    Aucun spambot n'est en mesure de reconstituer un tel formulaire, sans oublier que vous pourriez rajouter des fonctions totalement obsolètes dans les fichiers JS, voir même encrypter ou masquer les portions de code JS.

  • Fenêtre pop-up :
  • Aussi bête que cela puisse paraitre, une autre méthode simple et très efficace que seul un navigateur sera en mesure de reconstituer: pour poster un commentaire, vos visiteurs cliquent sur un lien en JS qui ouvre la fenêtre du formulaire. Le lien, affiché en JS par une fonction affiche_lien() va insérer un autre lien vers la deuxième fonction popup() qui, elle, contient l'URL du formulaire et le code pour ouvrir et centrer la fenêtre.

    Fichier JS externe form_01.js :

       function popup() {
          // hauteur et largeur de la fenêtre en pixels:
          var height=400;
          var width=400;
          // scrollbar (0=non, 1=oui)?
          var scroll_bar=0;
          // url de la page du formulaire:
          var url='http://monsite.tld/monformulaire.html'
    
          var str = "height=" + height + ",innerHeight=" + height;
          str += ",width=" + width + ",innerWidth=" + width;
          // centre la fenêtre
          if (window.screen) {
             var ah = screen.availHeight - 30;
             var aw = screen.availWidth - 10;
             var xc = (aw - width) / 2;
             var yc = (ah - height) / 2;
             str += ",left=" + xc + ",screenX=" + xc;
             str += ",top=" + yc + ",screenY=" + yc;
             if (scroll_bar) {str += ",scrollbars=yes";}
             else {str += ",scrollbars=no";}
             str += ",status=no,location=no,resizable=yes";
          }
          win = open(url, 'formulaire', str);
       }
    
       function affiche_lien(){
          document.write('<a href="javascript:popup();">Poster un message</a>');
       }
    
    Page HTML :
       <html>
       <head>
       <script language="JavaScript" src="form_01.js" type="text/javascript"></script>
       </head>
       <body>
       ...
       ...
       <script>affiche_lien();</script>
       ...
    

  • Evénements HTML :
  • Un utilisateur normal devra bien taper une portion de texte avant d'envoyer son message. Avec un simple événement comme onKeyUp, lorsqu'il va entrer son nom, une variable cachée recevra une valeur que votre script PHP/ASP ou Perl CGI va vérifier. Si elle n'est pas présente ou incorrecte, le script va rejeter le message posté. Dans cet exemple la valeur incorrecte initiale sera de 1350 et la bonne 893:

    Fichier HTML :

       <form name=formulaire action=mon_script.pl method=post>
       <input type=hidden name=evenement value=1350>
       ...
       Nom: <input type=text name=nom size=20 onKeyUp="document.formulaire.evenement.value=893">
       ...
       </form>
    

    Script Perl (ou autre) :

       #!/usr/bin/perl
       use CGI;
       $QUERY = new CGI;
       $EVENEMENT = $QUERY->param('evenement');
       if ($EVENEMENT != 893){
          print $QUERY->redirect(-url => "http://fbi.gov");
       }
       ...
       ...
    

    Idem mais en utilisant 3 variables dans un fichier JS externe pour obtenir notre valeur de 893:

    Fichier JS externe form_1.js :

       var topsecret=0;
       var soustraire=107;
       var valeur=1000;
    
    Fichier HTML :
       <form name=formulaire action=mon_script.pl method=post
       onSubmit="document.formulaire.evenement.value=topsecret-soustraire;">
    
       <input type=hidden name=evenement value=1350>
       ...
       Votre nom: <input type=text name=nom size=20 onKeyUp="topsecret=valeur">
       ...
       <input type=submit value='Poster le message'>
       </form>
    

    D'autres événements comme onMouseOver, onFocus etc feraient aussi bien l'affaire, tout comme onLoad (ou window.load) qui va simplement modifier automatiquement la valeur lors du chargement de la page dans un navigateur :

       <html>
       <head></head>
       <body onload="document.formulaire.evenement.value=893">
          ...
          <form name=formulaire action=mon_script.pl method=post>
    
          <input type=hidden name=evenement value=1350>
    
          Votre nom: <input type=text name=nom size=20>
          <input type=submit value='Poster le message'>
          </form>
          ...
       </body>
       </html>
    

  • Temps écoulé entre l'affichage de la page et l'envoi des données :
  • Il va de soi que le temps entre l'affichage de votre page HTML et l'envoi d'un éventuel commentaire devrait au moins être d'une dizaine de secondes. En postant l'heure exacte de l'affichage au script Perl/ASP/PHP, celui-ci va vérifier le nombre de secondes écoulées. On utilisera l'epoch (nombre de millisecondes/secondes depuis le 1er Janv 1970) avec soit un fichier JS externe, soit SSI (Server Side Includes).

    Fichier JS externe + code HTML :

       function print_epoch(){
          var thisdate = new Date();
          // getTime() retourne le nombre de MILLISECONDES depuis l'epoch:
          var epoch=thisdate.getTime();
          document.write("<input type=hidden name=epoch value="+epoch+">");
       }
    

       <form name=formulaire action=mon_script.pl method=post>
       <script>print_epoch();</script>
       ...
       Votre nom: <input type=text name=nom size=20><p>
       ...
       <input type=submit value='Poster le message'>
       </form>
    

    Fichier HTML seul avec SSI :

       <form name=formulaire action=mon_script.pl method=post>
       <!--#config timefmt="%s" -->
       <input type=hidden name=epoch value="<!--#echo var="DATE_LOCAL" -->">
       ...
       Votre nom: <input type=text name=nom size=20><p>
       ...
       <input type=submit value='Poster le message'>
       </form>
    

    Script Perl (ou autre) de récupération des données postées :

       #!/usr/bin/perl
       use CGI;
       $QUERY = new CGI;
       $EPOCH = $QUERY->param('epoch');
       if ((!$EPOCH)||($EPOCH!~/^\d{10,13}$/)){goto REDIR}
       # ne récupère que les secondes:
       $EPOCH=~s/^(\d{10}).*/$1/;
       $now=time;
       # moins de 10 secondes entre l'affichage de la page et l'envoi des données?
       if ($now-$EPOCH<10){
    REDIR:
          print $QUERY->redirect(-url => "http://fbi.gov");
       }
       ...
    

  • Masquer les éléments HTML :
  • Sans avoir besoin de faire appel à un système de cryptage, vous pouvez masquer votre formulaire en remplaçant les caractères par leur correspondance décimale avec les fonctions JS charCodeAt() et fromCharCode() et l'insérer tel dans votre page HTML ou mieux, dans un fichier JS externe. Vous pouvez tester ci-dessous:

    Entrez dans ce cadre votre code HTML :

    Cliquez sur "Masquer le code HTML" pour afficher le résultat dans ce cadre :

       

    Vous pouvez télécharger le code JavaScript utilisé dans cet exemple.

  • La balise <IFRAME> :
  • La balise <IFRAME> permet de charger une autre page dans votre page HTML principale. Son utilisation est donc très intéressante pour contrer les spams de commentaires en mettant votre formulaire dans un fichier HTML externe :

    Page HTML prinicpale :

       <html>
       <head></head>
       <body>
       ...
       Ceci est mon texte/article...
       ...
       <iframe src="formulaire.html" width=400 height=200 style="border:none;"></iframe>
       ...
       ...
       </body>
       </html>
    
    Page du formulaire (formulaire.html) qui sera chargée par <IFRAME> :

       <html>
       <head></head>
       <body>
       <form method=post>
       Nom:<input type=text name=nom><p>
       Email:<input type=text name=email><p>
       Commentaires:<textarea name=comment></textarea><p>
       <input type=submit value='Poster'>
       </form>
       </body>
       </html>
    
    Le résultat ci-dessous illustre cet exemple :

    Bien entendu, rien ne vous empêche de masquer le code d'appel à l'iframe dans votre page HTML avec la méthode décrite dans "Masquer les éléments HTML":

       <html>
       <head></head>
       <body>
       ...
       Ceci est mon texte/article...
       ...
       <script>
    document.write(String.fromCharCode(60,105,102,114,97,109,101,32,115,114));
    document.write(String.fromCharCode(99,61,34,102,111,114,109,117,108,97));
    document.write(String.fromCharCode(105,114,101,46,104,116,109,108,34,32));
    document.write(String.fromCharCode(119,105,100,116,104,61,52,48,48,32));
    document.write(String.fromCharCode(104,101,105,103,104,116,61,50,48,48));
    document.write(String.fromCharCode(32,115,116,121,108,101,61,34,98,111));
    document.write(String.fromCharCode(114,100,101,114,58,110,111,110,101));
    document.write(String.fromCharCode(59,34,62,60,47,105,102,114,97,109,101));
    document.write(String.fromCharCode(62));
    </script>
       ...
       ...
       </body>
       </html>
    


  • Forcer le spammeur à se piéger lui-même :
  • S'il y a une chose que les spammeurs détestent, c'est lorsque l'on décide de jouer avec eux: leur faire perdre leur temps et donc leur argent est la pire des choses qui puisse leur arriver. Il serait vraiment dommage de s'en priver...
    Dans cette partie, nous allons reprendre notre premier exemple (multiples fichiers JS externes) mais en encodant l'appel à la fonction affiche() avec fromCharCode(), puis nous allons dans la partie HTML créer un faux formulaire avec de fausses valeurs <INPUT>. Celui-ci sera invisible aux utilisateurs de votre site car caché dans des styles 'DISPLAY:NONE', mais bien visible aux spambots. Quant au vrai formulaire, il ne sera visible qu'aux utilisateurs ayant un navigateur digne de ce nom. En postant les données via ce formulaire bidon, le spammeur va tout simplement se piéger lui-même et sera blacklisté ou redirigé ailleurs:

    Partie HTML:

       <html>
       <head>
       <script language="JavaScript" src="form_01.js" type="text/javascript"></script>
       <script language="JavaScript" src="form_02.js" type="text/javascript"></script>
       <script language="JavaScript" src="form_03.js" type="text/javascript"></script>
       </head>
       <body>
       ...
       <!-- affiche le vrai formulaire en encodant "<script>affiche();</script>" -->
       <script>
          document.write(String.fromCharCode(60,115,99,114,105,112,116,62,97,102,102,105,99));
          document.write(String.fromCharCode(104,101,40,41,59,60,47,115,99,114,105,112,116,62));
       </script>
       ..
       ..
       <!-- formulaire pour les spambots -->
       <div style="display:none;">
       <form method=post action=piege.pl>
       Nom:<input type=text name=nom>
       Email:<input type=text name=email>
       Commentaires:<textarea name=comment></textarea>
       <input type=submit value='Poster'>
       </form>
       </div>
    

    Le script peut simplement renvoyer le spambot sur localhost pour lui faire perdre encore un peu plus de son temps.

    piege.pl:

       #!/usr/bin/perl
       use CGI;
       $QUERY = new CGI;
       print $QUERY->redirect(-url => "http://127.0.0.1");
       exit;
    


  • Forcer la compression gzip :
  • Vous disposez d'un serveur dédié ou mutualisé ? Dans ce cas, rien de plus simple : forcez la compression gzip uniquement pour l'affichage de votre formulaire.
    Activez mod_deflate depuis le terminal pour apache2 (pour apache 1, utilisez aenmod):

    
     # a2enmod deflate
    
    
    Ouvrez votre fichier apache2.conf et entrez les lignes suivantes :

    
     # Active gzip pour les fichiers suivants (les pages seront
     # compressées uniquement si le navigateur prend en charge gzip) :
     AddOutputFilterByType DEFLATE text/html
     AddOutputFilterByType DEFLATE text/plain
     AddOutputFilterByType DEFLATE text/xml
     AddOutputFilterByType DEFLATE text/css
     AddOutputFilterByType DEFLATE text/javascript
     AddOutputFilterByType DEFLATE application/x-javascript
    
     # Force la compression pour le formulaire :
     SetEnvIf Request_URI contac.html force-gzip
    
    
    Remplacez contac.html par le nom de la page de votre formulaire puis relancez apache. Comme son nom l'indique, la variable d'environnement force-gzip a pour effet d'envoyer systématiquement le contenu de la page au format compressé gzip, y compris si le destinataire ne le prend pas en charge, et donc de la rendre totalement illisible aux simples bots/scripts des spammeurs.
    Voici un aperçu de ce qu'ils obtiendront :
    
     �T��W��.�;Jt@#f��	��\̷
     �F��>}�[]�+�B7�������7��j�1f��4��0,�"���h.;�n�7���QYEJwEP�VYf
     �N w�����ؘ���
     ק���‚®.▒8ªìW._˜F 5+Ò┬§␤Õç	KŽÎý®æé
     ÆÕ¢÷ù┘#ðê«ô²ž—▒SÊÐ_éÝ▒à¹=̒ƒ ùàÃ緈™3≠MVê┐Ø
     €° $¶┘¿§Ù┌ñÕ5”R≤°┼”« ½8Ð"␍┼™┐6Ù┌⎻�=-�o����A�T
     �J_�C��Ln���N���ku@��^
     �ÆƗ1�
     Ŕ�ڑM�ٔ��я?�i'Ӆ�n8�ɲ����ޞ��F!��g�]�0�	��K�
     ;cv�>���x>
    
    
    Bien entendu, les moteurs de recherche (Google, Yahoo etc) ne seront pas en mesure de pouvoir récupérer le contenu de votre page pour l'indexer. Pour contrer ce problème, utilisez la méthode de l'IFRAME décrite ci-dessus pour afficher le formulaire dans votre page et forcez la compression gzip uniquement pour celui-ci (il est aussi possible d'exclure ces moteurs de recherche comme dans l'exemple suivant).


    II - Forums :

    La protection d'un gros forum peut sembler plus complexe car l'utilisation de petites astuces (JS, CSS...) n'est généralement pas envisageable. Fort heureusement, là encore, forcer la compression gzip est généralement suffisant.
    Voici un exemple avec le forum Yaab et un redoutable bot utilisé par les spammeurs : XRumer. Ce bot est capable de poster des centaines de spams, d'ouvrir des comptes utilisateurs si nécessaire et même de casser certains CAPTCHA. Cependant, il ne prend pas en charge la compression gzip. La capture d'écran ci-dessous (XRumer version 5.05 Palladium demo) montre clairement son impuissance dès lors que force-gzip est activé :

    XRumer

    L'activation de force-gzip doit se faire pour le script principal (visualisation et envoi des messages), en l'occurence YaBB.pl dans le cas du forum Yabb, et afin de laisser les crawlers indexer les messages, ceux-ci sont simplement ajoutés avec la directive BrowserMatch qui elle, annulera la compression gzip si nécessaire en activant la variable no-gzip.

    Fichier apache2.conf (ou httpd.conf) :

    
     # Active gzip pour les fichiers suivants (les pages seront
     # compressées uniquement si le navigateur prend en charge gzip) :
     AddOutputFilterByType DEFLATE text/html
     AddOutputFilterByType DEFLATE text/plain
     AddOutputFilterByType DEFLATE text/xml
     AddOutputFilterByType DEFLATE text/css
     AddOutputFilterByType DEFLATE text/javascript
     AddOutputFilterByType DEFLATE application/x-javascript
    
     # Force la compression gzip en cas d'appel au script du forum :
     SetEnvIf Request_URI YaBB.pl force-gzip
     # Désactivation si moteurs de recherche :
     BrowserMatch "Googlebot" no-gzip
     BrowserMatch "Yahoo\!" no-gzip
     BrowserMatch "msnbot\/" no-gzip
     BrowserMatch "Twiceler" no-gzip
     BrowserMatch "Ask Jeeves" no-gzip
     BrowserMatch "Gigabot" no-gzip
     BrowserMatch "VoilaBot" no-gzip
    
    
    Relancez Apache.


  • Méthodes à eviter:
  • Si, comme on vient de le voir, des méthodes très simples peuvent suffir pour éviter les spams de commentaires, d'autres sont à proscrire car totalement inutiles face aux spambots:
    -vérification du referer (HTTP_REFERER): les spammeurs peuvent forger celui-ci et vous faire croire qu'ils viennent de n'importe quel endroit, y compris de votre page de commentaires.
    -les cookies: un spambot peut très facilement accepter tous les cookies que vous lui donnerez et vous les retourner à chaque fois que vous les lui demanderez (il suffit juste de 5 ou 6 lignes de code pour le faire).
    -bloquer les IP à long terme: si vous bloquez les IP, ne les bloquez pas plus de quelques heures car les spammeurs utilisent des proxies et vous risqueriez de vous retrouver rapidement avec de très longues listes d'IP ne servant pas à grand chose sauf à ralentir terriblement votre site car le fichier .htaccess et des modules comme mod_rewrite ne sont pas réputés pour leur rapidité et ne sont pas fait pour gérer des centaines de lignes de code.