Je n’ai encore trouvé aucune page web parlant de la reconnaissance du type (spam/non-spam) basé sur son Message-ID. Et pourtant, Dieu ce que c’est fiable ! ! !
Rappel : le message-ID désigne de manière unique un mail. Lire la
RFC 822 si vous voulez
en savoir plus a son sujet.
Le principe a déjà été évoqué ici ou là, mais personne n'est jamais passé à l'acte :
utiliser le champ "Reference" ou le champ "In-Reply-to" pour détecter les
hams.
Ces champs sont utilisés par les bons MUAs pour faire du threading ; le premier contient
tous les Messages-ID des mails qui le précèdent dans le thread, le second uniquement le
Message-ID du mail auquel il réponds, et sont mis en place par les "bons" logiciels.
Environ 95% des mails parvenus en réponse à un autre mail ont l'un des deux champs (voire les deux); parmis les logiciels qui n'en mettent pas
on citera les célèbres Microsoft Exchange et Lotus Notes. Si votre MUA ne met pas en place
de tels champs, je ne peux que vous conseiller de le mettre a la poubelle, et d'en changer si c'est possible.
Pour plus d'informations au sujet de ces champs, vous pouvez aller voir sur la page de D. Bernstein (attention, certaines pages de son site sont un peu "faussés").
Revenons donc a ces champs : lorsque nous recevons un mail, nous pouvons parfaitement regarder si l'un de ces champs contient le Message-ID d'un ham que
nous avons reçu ou envoyé précédemment.
Comme nous savons qu'il est très difficile voire impossible pour le spammeur de deviner les Messages-ID des mails légitimes recus précedemment, il ne pourra pas tenter de forger ce champ. Tout au plus pourra-t-il y mettre quelque chose
dedans, mais en aucun cas y mettre un Message-ID d'un de vos hams (car comment
le connaitrait-il ??).
Donc tous les mails dont le champ References ou In-Reply-To pointe vers un ham sera un ham !
Ainsi sur les mailing-lists auxquels vous êtes inscrits (enfin celles qui sont pas filtrés
contre le spam de manière efficace), seul le premier message d'un thread aura besoin d'être
filtré par votre couteux anti-spam actuel.
Sur vos courriers personnels cela arrivera moins souvent, mais si vous reconnaissiez les Message-IDs de vos mails ? Ou si vous trouviez un moyen de stocker quelque part les Message-IDs des mails que vous avez envoyé ? Et bien nous allons voir ça
aussi.
Un spammeur pourra tenter de vous envoyer un mail anodin, sans HTML, sans parler de Viagra, attendre que le message-ID soit mémorisé comme ham (puisque nous allons mémoriser les Messages-ID automatiquement, hors de question de le faire a la main, ou de regarder tous les anciens mails
a la recherche de ceux-ci).
Mais pour le moment, je n'ai jamais vu de tels mails, et puis s'ils se mettaient a en faire, ça doublerait le nombre de mails qu'ils vont devoir envoyer, donc divisera par 2 le nombre de spams qu'ils pourront envoyer.
Et dans ce cas cette vérification pourrait être intégrée dans SpamAssassin, comme un simple règle, ou bien on pourra changer les règles de mémorisation du Message-ID...
Quand au spammeur qui parviendra a ré-utiliser les règles que vous utilisez pour reconnaitre les Messages-ID des mails que vous auriez envoyés, il sera balaise. En fait c'est même impossible si l'algorithme générateur de Messages-ID de votre MUA est compliqué, ou si vous créez la base de données de Message-IDs a partir des mails reçus ceux que vous avez employés.
La méthode la plus simple pour créer votre base de données, sera la règle procmail suivante, qui mémorisera les messages-ids des hams (à placer après l'anti-spam donc) :
# Mettre les spams dans une boite a part :0: * ^X-Spam-Status: Yes spam # si ce n'est pas un spam, sauver le message-id :0E c :message-id.block | echo `formail -x Message-ID: | tr -d '<>[:cntrl:]' ` >> $MAILDIR/.message-id
Avec ça votre fichier "$MAILDIR/.message-id" ne fera que grossir, de temps en temps vous pourrez supprimer les premières lignes de celui-ci.
Cette solution consiste à parser les logs (récents) de postfix, et de stocker TOUS les Messages-ID qui y sont trouvés
dans un fichier. Et bien sur, j'ai rien trouvé de mieux que de faire ça avec un script appelé toutes les 3 minutes
par la crontab. Ah oui, c'est crade !!
Avec ca tous les mails envoyés et reçus par les utilisateurs du serveur seront utilisés, donc aussi tous les Spams. Dès que les
spammeurs essayeront de contourner, ce sera cuit. Par contre du coup cette cochonnerie reconnait tous les Messages-IDs des
mails que vous avez envoyés, sans autre effort supplémentaire.
Voici donc le code :
#!/bin/bash sed -ne '/message-id/!d;s/.*message-id= *<\(..*\)>.*/\1/p' /var/log/mail.log* | sort -u > /tmp/message-ID
Et pour votre crontab :
*/3 * * * * /usr/local/bin/liste-MID
Les connaisseurs se demandent pourquoi ne pas utilier formail. L'option permettant de reconnaitre les doublons de formail fait a peu près ce que faisait la solution procmail !! Malheureusement il n'utilise pas un format parsable par fgrep, mais avec quelques modifications il en serait effectivement capable. Et on pourrait même imaginer lui permettre de vérifier directement si les champs References ou In-Reply-to pointent sur un des mails contenus la-dedans en une opération. J'ai pas envie de m'amuser a le patcher pour ça (en fait surtout pas le temps), mais vu que c'est la méthode la plus propre, je vous encourage a le faire (si je décide pas de le faire moi-même dès que j'ai du temps) !
Bon, maintenant que la base de données est faite proprement, il n'y a qu'a faire le code pour vérifier si les champs References ou In-Reply-To pointent sur un de ces mails. Alors pour ça (en procmail) :
# Checker si References et In-Reply-To pointent sur un message-ID connu
REF_OK=no
REFERENCES="`formail -c -x References -x In-Reply-To: | tr -d '<>[:cntrl:]'`"
:0
* REFERENCES ?? @
* ? (echo $REFERENCES | fgrep -i -w -f /tmp/message-ID)
{ REF_OK=yes }
# Sinon, passer les anti-spams
# Ici juste un Spam-Assassin
:O E fw
| spamassassin
Je stocke dans une variable le fait que le nouveau mail ne passe pas le test, mais il faut dire que mon .procmailrc est assez complexe, avec pleins d'anti-spams et d'expériences de détection de spams dans tous les sens... D'ailleurs là j'ai simplifié pas mal l'appel aux anti-spams.
Si la votre base de données est triée (ce qui est le cas avec le script de la crontab), il est possible de se servir de cette propriété pour gagner un peu de temps CPU en faisant de la sorte (non testé):
formail -c -x References -x In-Reply-To | xargs printf "%s\n" | cut -f1 | sort -u | join Message-ID - | head -1
Pour faire la reconnaissance et la sauvegarde des Message-ID recus personnellement, j'en ai déjà parlé, ça passerait par patcher formail (ou faire un utilitaire spécialement
pour ça).
Mais là ou ça pourrait devenir intéressant, ce serait d'avoir un serveur de mail qui logue les Messages-IDs de tous les mails sortants (autrement dit s'occupe
de créer la base de données), et permet a tout le monde de les utiliser (enfin, tant que
le "tout le monde" n'est pas trop nombreux)... Du coup tous les mails sortants que l'on
enverrait seraient inscrits dans la base, et comme ça, pas la peine d'appliquer avec
ce qui va suivre.
A vos éditeurs de texte pour modifiez le code source de votre MTA préféré donc !!
Il y a plusieurs solutions pour reconnaitre ses Messages-IDs, dont entre autres :
send-hook . my_hdr Message-ID:`date "+>%Y%m%d%H%m%S.\`pwgen -1\`@sous-bock.ipv6.netlibre.info>"`Bien sûr, vous adapterez un peu pour avoir votre format personnalisé (pwgen, pour ceux qui connaissent pas c'est un générateur de mot de passe, ici utilisé pour rajouter de l'entropie).
Prenons le cas de l'Efrei (mon école).
Je regarde les Message-ID qui me parviennent de mes camarades pour commencer (Pour faire ça facilement,
vous prenez mutt, vous rajoutez 'color header green default "^Message-ID:"'
dans votre .muttrc, et les Message-ID seront mis en valeur. Puis vous appuyez sur 'h' pour voir les header, et
z'aurez qu'a vous déplacer avec les touches habituelles pour faire ça très vite. Ou alors vous affichez
carrement le Message-ID dans l'index des mails...). De là on constate que :
#!/bin/bash
BROADCAST=192.168.1.255
for i in `ping -c 2 $BROADCAST | sed -n "s/64 bytes from \(192\.168\.[0-9]*\.[0-9]*\):.*$/\1/p" | sort -u` ; do
host $i | sed -e "s/.*domain name pointer \(.*\)\./\1/";
done;
A part quelques machines particulières, c'est un bon début... Maintenant on va mixer tout ça :
#Choper les références connues
REFERENCES="`formail -c -x References -x In-Reply-To: | tr -d '<>[:cntrl:]'`"
REF_OK=no
# Checker si References et In-Reply-To ont une machine connue !
:0
* REFERENCES ?? @
* ? (echo $REFERENCES | fgrep -i -f $HOME/Mail/.authorized_hosts)
{ REF_OK=yes }
# Checker les mutt de l'EFREI
:0 EH
* ^(Message-ID|In-Reply-To|References): 20.*[0-9]*\.G[A-Z][0-9]*@efrei\.fr
{ REF_OK=yes }
:0
* REF_OK ?? no
{
#Lancement divers tests de spams
#Poubellisation
:0:
* ^X-Spam-Level: \*\*\*\*\*\*\*\*\*\**
Spammeux
}
# si ce n'est pas un spam, sauver le message-id :0c :message-id.block | echo `formail -x Message-ID: | tr -d '<>[:cntrl:]' ` >> $MAILDIR/.message-id
Les personnes suivantes m'ont aidés a améliorer cette page :
Je viens de constater à l'instant que chez certains FAI les Messages-IDs sont réécris (merci EVC!).
Rebonjour, j’ai ce message dans mes logs : Non-zero exitcode (1) from " (echo $REFERENCES | fgrep -i -f $MAILDIR.authorized_hosts)"
il manque un exitcode ?
Peux-tu m’indiquer ce que tu as mis exactment dans le sendhook ? Et donner un des Message-ID ainsi généré ?
Sinon, si tu souhaites que seul le domaine apparaisse (et laisser à mutt le soin de générer tout seul le message-id selon son algo), tu as l’option : set hidden_host = yes
Enfin, dans certaines configurations, le MTA (sendmail, postfix, qmail, etc) remplace le message-ID par le sien.
Et est-ce que tu as bien installé pwgen ? (sous debian apt-get install pwgen).
Le Message-ID des mails sous mutt a quel forme ? <20050323140412.GA1983@sous-bock.netlibre.info> -> c’est mutt qui a généré le message-ID parce que le hook a échoué (ou autre chose ?). (La lettre G est fixe, puis suis une lettre majuscule, puis le PID du process de mutt. Au début, c’est la date). Si ton message-ID ne suit pas ce format, c’est postfix qui réécrit ton message-ID.
Au fait c’est le MTA qui change le message-id comme par exemple postfix. Il faut donc ordonné à postfix de ne pas changer le message-id. (Si cela a été fait avant par mutt biensûr) Ceci ne peut ce faire qu’avec la dernière version, la 2.2.2 !
Bonjour,
J’aimerais connaître l’algorithme de Message ID des 4 plus gros MTA’s sous Unix, à savoir Exim, PostFix, SendMail et Qmail.Je l’ai déjà pour Exim, et en partie pour SendMail, mais tout info supplémentaire est la bienvenue, mon but étant de produire un code capable de reconnaitre si le message ID d’un message est valide ou non.
Merci ! A+
Clément