19 fév. 2010
Halte là !
Par Christophe de saint leger le vendredi, février 19 2010, 12:43 - PHP - Lien permanent
Sécurisez vos formulaires contre les spams

Vous avez un banal site vitrine , un livre d'or ou autres formulaires de contact / commentaires , sans protection , même minime , vous allez rapidement voir apparaître des messages non sollicités , qui peuvent même parfois se révéler dangereux .
Cet article vise à donner une solution ( parmi beaucoup d'autres ) pour éviter ce genre de désagrément , et sans le moindre captcha .
Nous allons prendre un simple formulaire de contact pour l'exemple
Le code de base , sans aucune protection
Le formulaire
<form name="contact" method="POST" action="send.php" >
<table>
<tr>
<td>
Pseudo :
</td>
<td>
<input type="text" name="pseudo" >
</td>
</tr>
<tr>
<td>
Mail :
</td>
<td>
<input type="text" name="email" >
</td>
</tr>
<tr>
<td>
Message :
</td>
<td>
<textarea name="message" ></textarea>
</td>
</tr>
<tr>
<td>
<input type="submit" name="envoyer" value="envoyer" />
</td>
</tr>
</table>
</form>
Envoi du mail
<?php /* * send.php * */ //récupération et filtrage des données $tData = filter_form( $_POST, "utf-8" ); //envoie du mail sendMail( $tdata ); ?>
Voilà , quoi de plus simple .. mais quoi de plus vulnérable par le spam !!!!
Note: je ne traiterais pas ici des fonctions filter_form() et sendMail() , n'étant que des fonctions fictives pour éclaircir au maximum le code .
Protection 1 : rendre le formulaire unique
Et oui ce n'est pas parce que le formulaire est là qu'une personne malveillante doit y passer pour envoyer le mail , ce qui permet aux "pirates" de forger des requêtes , envoyé soit par une de leurs victimes , un robots ou autres méthodes détournées .
Pour rendre le formulaire unique , nous allons lui ajouter un jeton , qui sera changeant constamment , ainsi avant l'expédition du mail , l'on vérifie que le jeton est là et valide
Voilà le formulaire modifié
<form name="contact" method="POST" action="send.php" >
<table>
<tr>
<td>
Pseudo :
</td>
<td>
<input type="text" name="pseudo" >
</td>
</tr>
<tr>
<td>
Mail :
</td>
<td>
<input type="text" name="email" >
</td>
</tr>
<tr>
<td>
Message :
</td>
<td>
<textarea name="message" ></textarea>
</td>
</tr>
<tr>
<td>
<input type="submit" name="envoyer" value="envoyer" />
<input type="hidden" name="jeton" value="<?php echo md5('graindesel'.date('Y-m-d h:i:00'));?>" />
</td>
</tr>
</table>
</form>
Et au niveau de send.php , il nous suffit d'ajouter la vérification du jeton de la façon suivante :
<?php
/*
* send.php
*
*/
//récupération et filtrage des données
$tData = filter_form($_POST,"utf-8");
//cree un tableau de 0 à 10
$validite = range(0, 10) ;
//initialise le resultat
$valide = false ;
//vérifie le jeton
foreach($validite as $v) {
$valide |= ( $_POST['jeton'] == md5('graindesel'.date('Y-m-d h:i:00', mktime() - $v * 60)));
}
if( !$valide ){
//redirection vers une page d'erreur
}else{
//envoie du mail
sendMail($tdata);
}
?>
Contrairement au formulaire initial cette fois le "pirate" est obligé de passer par le formulaire pour envoyer le mail , le jeton étant valide 11 minutes , un internaute devra remplir et envoyer ce formulaire en maximum 11 minutes , ce qui est largement faisable . 
Protection 2 : filtrage anti-spam
La protection du formulaire unique permet déjà de réduire de façon notable l'envoie de spam via cette page , maintenant certains réussirons toujours à passer outre , rien de bien compliqué à celà .
La derniére solution avant expédition , est d'utiliser un service enti-spam tel que akismet
Akismet est un Web-service à qui nous allons envoyer les données du formulaire , en réponse nous arons un simple booléen qui nous indiquera si oui ou non le message semble être un spam .
Enregistrement Akismet
Il vous faut une clef ( gratuite ) , pour celà allez vous enregistrer sur le site d'akismet
Utilisation akismet
Le site vous propose de nombreux plugins déjà prêts pour des applications comme Dotclear , Wordpress , punBB ect ...
Mais aussi des "class" php pour des scripts perso comme le notre .
Nous allons donc télécharger la classe proposé par le site achingbrain.net
L'utilisation est trés simple, dézipez l'archive afin de rendre la classe accessible par votre serveur web ... ( je vais la mettre au même endroit que send.php pour l'exemple )
et voilà la modification de send.php pour utiliser ce service :
<?php
/*
* send.php
*
*/
//récupération et filtrage des données
$tData = filter_form($_POST,"utf-8");
//cree un tableau de 0 à 10
$validite = range(0, 10) ;
//initialise le resultat
$valide = false ;
//vérifie le jeton
foreach($validite as $v) {
$valide |= ( $_POST['jeton'] == md5('graindesel'.date('Y-m-d h:i:00', mktime() + $v * 60)));
}
if( !$valide ){
//redirection vers une page d'erreur
}else{
//Test AKISMET
$APIKey = 'aoeu1aoue';
$MyURL = 'http://www.lindev.fr/contact/';
$akismet = new Akismet($MyURL ,$APIKey);
$akismet->setCommentAuthor( $tdata['pseudo'] );
$akismet->setCommentAuthorEmail( $tdata['email'] );
$akismet->setCommentContent( $tdata['message'] );
$akismet->setPermalink( $MyURL );
if($akismet->isCommentSpam()){
//redirection vers une page d'erreur
}else{
//envoie du mail
sendMail($tdata);
}
}
?>
Cette fois non seulement l'utilisateur doit passer par le formulaire , mais en plus le message sera vérifié par un service anti-spam , ce qui vous permet d'éliminer plus de 90% des mails/messages non sollicités qui peuvent provenir de ce genre de formulaire .
Et ce sans captcha 
Autre barrière:
Il existe encore une autre barrière , si vous êtes encore embêté , l'interrogation de listes rbls , qui vous indique si l'adresse ip du client qui remplis votre formulaire est listé comme spammeur ou non ..
Juste pour information , en voici une pour exemple :
http://bsb.spamlookup.net/
A bientot , Ch.

Commentaires
Une autre solution très facile à mettre en place consiste à ajouter un champs input que l'on affiche pas.
Si il est transmis rempli c'est forcément envoyé par un robot.
C'est pas du 100% mais c super simple à mettre en place.
En tt cas merci pour l'article.
Cyruss
Cyruss, ce n'est pas forcément un robot. En effet tu va cacher ton champ de formulaire très certainement avec CSS, or tous utilisateurs -suivant ce qu'ils utilisent pour accéder à ton formulaire- n'auront pas la prise en charge de CSS. Aussi, d'un point de vue accessibilité ceci peut poser problème.