Blog-like notes

Du traitement du courrier non-sollicité

Comme expliqué dans une note précédente, je ne crois pas aux vertus (?) de l’obfuscation des adresses de courrier électronique, et je ne fais aucun effort particulier pour cacher la mienne aux yeux des collecteurs d’adresses. Ma boîte de réception n’est pas devenue une poubelle pour autant, grâce aux deux mesures de protections que j’expose ici.

Première ligne de défense : SPF

SPF, Sender Policy Framework, est un protocole par lequel l’administrateur d’un domaine peut déclarer les machines autorisées à relayer du courrier venant de ce domaine. Cela permet à un serveur de messagerie de refuser les messages transmis par une machine non autorisée, qui sont probablement frauduleux (l’émetteur essaie de se faire passer pour un autre).

Le principe

L’administrateur d’un domaine publie une politique SPF sous la forme d’un enregistrement DNS de type TXT (ou SPF, mais dans les faits ce type spécifique est très peu utilisé), énumérant les machines habilitées à relayer le courrier de ce domaine.

Par exemple, le domaine incenp.org a l’enregistrement suivant :

v=spf1 mx -all

Il signifie que la machine pointée par l’enregistrement MX de ce même domaine est autorisée à en relayer les courriers, et que c’est la seule ; tout courrier en provenance d’une quelconque autre machine doit être considéré comme une erreur (« -all »).

Un serveur de messagerie peut vérifier la légitimité d’un client sitôt que celui-ci a annoncé l’adresse de retour, dans les premières étapes du dialogue SMTP — avant même que le client ne transmette effectivement le courrier. Si le domaine figurant dans l’adresse de retour publie un enregistrement SPF, on vérifie que l’adresse du client est mentionnée dans ledit enregistrement, auquel cas on sait que le client est légitime et que le message peut être accepté ; dans le cas contraire, le message peut être soit refusé, soit au moins marqué comme suspect.

Mise en œuvre

J’utilise tumgreyspf pour mettre en œuvre la vérification SPF sur mon serveur de messagerie. Le paquet correspondant sous Debian s’appelle simplement tumgreyspf.

Par défaut, tumgreyspf fait à la fois du greylisting et de la vérification SPF. Seule cette dernière fonctionnalité m’intéresse (le greylisting est une technique anti-spam dont l’efficacité n’est plus à démontrer, mais je ne l’aime pas). Pour désactiver le greylisting, il suffit d’éditer le fichier /etc/tumgreyspf/default.conf et de régler CHECKERS à « spf » uniquement :

[…]
CHECKERS = spf
[…]

Il faut ensuite configurer le serveur SMTP pour qu’il confie à tumgreyspf le soin de vérifier si un client est autorisé au sens de SPF. Pour Postfix, ça se fait dans /etc/postfix/main.cf :

smtpd_recipient_restrictions =
      permit_mynetworks,
      permit_sasl_authenticated,
      reject_unauth_destination,
      check_policy_service unix:private/tumgreyspf
tumgreyspf_time_limit = 3600

et dans /etc/postfix/master.cf :

tumgreyspf	unix	-	n	n	-	-	spawn
 user=tumgreyspf	argv=/usr/bin/tumgreyspf

SPF en action

Voici concrètement ce que donne, dans les journaux du serveur, une tentative de remettre un message par une machine non autorisée :

Sep 20 21:03:38 mail.incenp.org postfix/smtpd[15603]: NOQUEUE: reject: RCPT
from mail.egfe.com[212.235.43.133]: 550 5.7.1 <dgouttegattat@incenp.org>:
Recipient address rejected: QUEUE_ID="" SPF Reports: 'SPF fail - not
authorized'; from=<unitednation@un.org> to=<dgouttegattat@incenp.org>
proto=EMSTP helo=<mail.egfe.com>

Que s’est-il passé exactement ? La machine à l’adresse 212.235.43.133 s’est présentée sous le nom mail.egfe.com et a annoncé avoir un message pour moi venant de <unitednation@un.org>. Que dit l’enregistrement SPF du domaine un.org ?

$ dig un.org TXT +short
"v=spf1 ip4:157.150.185.0/27 ip4:157.150.34.0/26 a:mx3901.un.org a:mx3902.un.org -all"
$ dig mx3901.un.org A mx3902.un.org A +short
195.47.221.40
195.47.221.41

Donc, les machines autorisées à envoyer le courrier de un.org sont celles situées dans les réseaux 157.150.185.0/27 et 157.150.34.0/26, ainsi que les deux machines 195.47.221.40 et 195.47.221.41 ; absolument aucune autre machine n’est autorisée.

L’adresse du client mail.egfe.com ne correspond à aucune des adresses indiquées, il est débouté et le message ne va pas plus loin.

Deuxième ligne : filtrage bayésien

Le filtrage bayésien est une technique classique de lutte contre le spam. En quelques mots, un filtre bayésien détermine la probabilité qu’un message donné soit indésirable ou légitime (« ham », par opposition à « spam ») après avoir « appris » à reconnaître les éléments apparaissant préférentiellement dans ces deux catégories de messages.

Avant d’aborder la mise en place d’un tel filtre, je dois d’abord expliquer ce que deviennent les courriers arrivant sur mon serveur. Postfix, le serveur SMTP, confie les messages destinés à un utilisateur local à procmail (mailbox_command = /usr/bin/procmail, dans la configuration de Postfix) ; procmail se charge alors de délivrer ces messages en fonction des règles définies par l’utilisateur dans son fichier ~/.procmailrc. Dans mon cas, ces règles instruisent procmail de stocker les messages dans des boîtes au format Maildir dans mon répertoire personnel. Ces boîtes sont finalement servies en IMAP à mon client de messagerie.

Le filtre bayésien, implémenté par bogofilter, prend place lors du traitement des messages par procmail, grâce aux deux règles suivantes :

:0fw
| bogofilter -e -p

:0
* ^X-Bogosity: Spam
spam/input/

La première règle envoie inconditionnellement le message à bogofilter, qui l’analyse et lui ajoute un en-tête spécifique, X-Bogosity, indiquant le résultat de l’analyse (« Spam », « Ham » ou « unsure », suivi du degré de « spamicité »); procmail récupère ensuite le message en sortie de bogofilter et lui applique la seconde règle, conduisant à stocker le message dans la boîte spam/input/ s’il a été marqué comme étant probablement indésirable (s’il a au contraire été marqué comme légitime, ou si bogofilter n’a pas pu se prononcer avec suffisamment de certitude, procmail place le message dans la boîte par défaut, qui est l’inbox, la boîte de réception principale.

Il reste ensuite à « entraîner » bogofilter, c’est-à-dire lui fournir des exemples de messages légitimes et de messages indésirables. Je fais cela via deux boîtes dédiées, spam/classify-ham/ (pour les messages légitimes) et spam/classify-spam/ (pour les messages indésirables). Le script suivant, appelé quotidiennement, exécute bogofilter en mode apprentissage sur chacune de ces boîtes, puis les vide :

#!/bin/bash

BASEDIR=/home/damien/Mail/spam

if [ $(ls $BASEDIR/classify-spam/cur | wc -l) -gt 0 ]; then
        bogofilter -s -B $BASEDIR/classify-spam
        rm -f $BASEDIR/classify-spam/cur/*
fi

if [ $(ls $BASEDIR/classify-ham/cur | wc -l) -gt 0 ]; then
        bogofilter -n -B $BASEDIR/classify-ham
        rm -f $BASEDIR/classify-ham/cur/*
fi

Ainsi, à la réception d’un message indésirable dans ma boîte principale, je n’ai qu’à le déposer dans la boîte spam/classify-spam/ pour que bogofilter apprenne à le reconnaître comme tel ; si jamais un message est identifié à tort comme indésirable (faux positif) et arrive donc dans /spam/input/, je n’ai qu’à le copier dans spam/classify-ham pour ajuster le filtre.

Conclusion : quelle efficacité ?

Le filtrage bayésien est d’une efficacité redoutable. Trois semaines d’apprentissage ont suffi pour qu’au moins 90 % des messages indésirables soient correctement reconnus. Aujourd’hui, après deux ans d’utilisation, seuls deux ou trois messages par mois (sur environ 300) passent au travers des mailles du filet ; je n’ai recensé qu’un seul faux positif au cours de ces deux ans.

En consultant les journaux de mon serveur sur un mois, je constate que 34 messages ont été refusés suite à une vérification SPF. En première approximation, c’est donc environ 10 % du traffic indésirable qui est bloqué par l’application de SPF.