
Tous mes sites sont plus ou moins touchés par le spam de commentaires.
Que ça soit les forums (phpBB), les blogs (DotClear ou solution maison), mon wiki...
J'ai d'abord essayé les techniques suggérées par chaque solution :
- filtre antispam pour DotClear genre Spamplemousse
- captcha pour mon blog
- diverses techniques pour phpBB (mots interdits, modifications des formulaires pour contourner les robots)
- inscription obligatoire sur le wiki
Mais finalement toutes ces solutions sont :
- fastidieuses à maintenir
- pas forcément efficaces
- spéficiques à chaque produit
Récemment je suis tombé sur une technique assez élégante que je teste depuis plusieurs jours et qui fait ses preuves.
LinkSleeve est un site qui centralise les liens postés dans les formulaires.
Dès qu'un lien est un peu trop répété, le site suppose qu'il s'agit d'un spam.
L'intégration est assez facile et la solution générique puisqu'elle se base sur des messages XML-RPC.
Comme tous mes sites sont programmés en PHP, j'ai fait un petit script que j'inclue sur toutes mes pages. Si le contenu posté par l'utilisateur passe l'ensemble des tests, le script rend la main au programme initial sans rien dire. Sinon on fait un
die pour calmer le spammeur.
Le
die fait donc que le spammeur voit une page blanche au lieu du résultat attendu. C'est très moche mais finalement ça a quelques avantages :
- c'est très facile à intégrer dans les différents sites : on inclue le script, on n'a pas besoin de tester le code de retour ni de prendre de mesures en fonction de celui-ci
- ça déstabilise le spammeur : au lieu d'avoir un message "votre message contient du spam" ce qui pourrait l'inviter à essayer jusqu'à contourner le système, il peut penser à un bug du site
Evidemment il faut éviter au maximum les faux-positifs ;-)
Voilà à quoi ressemble aujourd'hui le script que j'utilise :
<?
# log the spam and quit
function spam_log($reason)
{
global $spam_input;
global $SERVER_NAME;
# here we can log to a file to monitor the spam
# ...
die;
}
# get POSTed data
$spam_input=implode(" ",$_POST);
# all in one big line
$spam_input=str_replace("\n"," ",$spam_input);
$spam_input=str_replace("\r","",$spam_input);
# if the POSTed vars do not contain any URL, no need to check for spam...
if (!preg_match('#http#i',$spam_input)) return;
# if there are too many urls we suppose it is spam...
if (preg_match('#(http[^ ]* *){3}#i',$spam_input)) spam_log('http');
# basic list of forbidden words
if (preg_match('#(viagra|pharmacy|casino|...)#i',$spam_input)) spam_log('word');
# try linksleeve database
include('xmlrpc.php');
$spam_f=new xmlrpcmsg('slv',
array(new xmlrpcval($spam_input, "string"))
);
$spam_c=new xmlrpc_client("/slv.php", "www.linksleeve.org", 80);
$spam_r=$spam_c->send($spam_f);
$spam_v=$spam_r->value();
if (!$spam_r->faultCode())
{
$spam_theval=$spam_v->scalarval();
if ($spam_theval!=1) spam_log('sleeve');
}
?>
Attention, c'est du "quick & dirty (tm)", et c'est adapté pour mes besoins maisons. En gros les étapes sont :
- On créé une grosse variable qui contient tous les champs POSTés par l'utilisateur, et on teste cette grosse variable (astuce pour être facilement adaptable à tous les sites).
- Si le site ne contient pas d'URL, on peut quitter tout de suite, c'est peu probable que le commentaire contienne du spam, et sinon il ne sert à rien...
- Si le site contient beaucoup d'URL collées les unes aux autres, c'est sûrement du spam.
- Si le site contient une liste de mots interdits, on considère que c'est du spam (car on sait déjà qu'il y a une URL dans le commentaire).
- Si on a passé tous ces tests on essaye la base LinkSleeve.
J'ai affiné ma liste de mots à partir des URL qui sont filtrées par LinkSleeve justement, ça me permet d'éviter de trop "bourriner" LinkSleeve.
Certains scripts suggérés par LinkSleeve ne testent d'ailleurs pas la présence d'une URL dans le contenu avant de soumettre celui-ci, alors que ça économise pas mal de requêtes. Heureusement tous les commentaires ne contiennent pas forcément un lien...
Au final je récupère un joli fichier de log, qui me permet d'affiner un peu plus mon script !
J'ai hésité entre l'anglais et le français pour ce billet, l'anglais était adapté vu que les commentaires de mon code sont déjà en anglais, mais maintenant que je suis agrégé sur planet.amglr.net, je ne peux plus tout me permettre :-p13 commentaire(s)...