28 avril 2024

Tuto Messagerie, partie IV : Optimisation de Postfix

Tutoriel révisé en décembre 2022 / Debian 11

Dans cette quatrième partie de ma série d’articles sur la mise en place d’un serveur mail complet, nous allons optimiser Postfix avec la mise en place de quelques sécurités supplémentaires.

I – Sécurisation SMTPS et Submission

La partie II, consacrée à Postfix laisse dans notre configuration une potentielle future faille.

Vous le savez, un SMTP externe communiquera avec le votre via le port 25, mais imaginons qu’un instant, un serveur se connecte à votre port 587…
Et bien, il ne sera pas embêté. Pour le moment, ce n’est pas bien méchant car il suivra les restrictions qu’il aurait rencontré via le port 25, mais si nous mettons en place des restrictions différentes selon les services (et c’est ce que nous ferons plus tard), et bien, on risque d’avoir des surprises.

Autant y remédier de suite en bloquant la possibilité à un serveur SMTP de se connecter la ou il ne doit pas.

On édite le fichier /etc/postfix/master.cf :

[...]
submission inet   n   -   y   -   -   smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
smtps      inet   n   -   y   -   -   smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
[...]

Pour ces deux services, la directive smtpd_client_restriction du main.cf est remplacée : on permet les utilisateurs connectés et on rejette le reste.

 

II – Antiforge

A – Explication

Derrière ce terme, se cache quelque de tout simple : le fait de pouvoir modifier (forger) sans vergogne l’adresse de l’expéditeur. Je m’explique :

  • Depuis votre logiciel de messagerie, si vous modifiez l’adresse d’expéditeur par nimportequoi@domaine1.fr, le mail est expédié sans aucun soucis.
  • De la même façon, un MX distant peut tout à fait présenter un mail auprès de notre serveur avec un FROM TO : toto@domaine1.fr , sans que cela ne gène le moins du monde.

On va donc rajouter une restriction au moment de la vérification du sender afin de limiter tout cela.

On édite le fichier /etc/postfix/main.cf et on ajoute dans la directive smtpd_sender_resctriction :

smtpd_sender_restrictions =
  reject_sender_login_mismatch,
  permit_mynetworks,
  [...]

Cette nouvelle directive s’appuie sur une sender_login_maps, qu’on va déclarer plus bas :

smtpd_sender_login_maps = ldap:/etc/postfix/ldap/virtual_senders.cf

On va créer le fichier qui va faire le lien avec le ldap : /etc/postfix/ldap/virtual_senders.cf :

server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = dc=debugo,dc=fr
scope = sub
query_filter = (|(&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES))(&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES)))
result_attribute = mail mailaliasto

Simple, cela retourne le propriétaire de la boite demandée si il y en a un.

Ensuite, deux cas de figures :

  • Si le client est SASL, il faut qu’il soit le propriétaire du mail pour que le mail soit accepté.
  • Si le client n’es pas en SASL et que la boite a un propriétaire, le mail ne sera pas accepté.

Vite fait, je reviens bien sur la distinction TLS et SASL :

  • Client SASL veut dire que le client est authentifié : un utilisateur.
  • Client Non SASL veut dire que c’est un client non authentifié, un serveur MX.

A ne pas confondre avec TLS (ou SSL) qui est la sécurité appliquée à la connexion.

On recharge Postfix :

# postfix reload

B – Pour le fun

Imaginons que dans notre schéma LDAP, nous ayons un attribut mailaliassend qui stipule si un alias a le droit ou non d’envoyer des mails. Après tout, pourquoi pas…

Notre fichier /etc/postfix/ldap/virtual_senders.cf pourrait ressembler à cela :

server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = dc=debugo,dc=fr
scope = sub
query_filter = (|(&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES)(mailaliassend=YES))(&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES)))
result_attribute = mail mailaliasto

La puissance du LDAP, tout simplement…

 

III – Contrôle d’accès

Dans sa grande générosité au niveau de ses possibilités, Postfix permet également d’effectuer des vérifications d’accès à l’aide de quatre contrôles :

  • check_client_access
  • check_helo_access
  • check_sender_access
  • check_recipient_access

Dans le cadre du renforcement de notre serveur Postfix, seul check_sender_access sera vraiment obligatoire, les autres, c’est au cas pas cas.

Ces vérification s’appuient sur des données formatées de la sorte :

111.111.111.111 REJECT
// ou bien
toto@domaine1.fr OK

Bien que le OK soit implicite (si pas d’entrée, c’est OK par défaut), il peut être nécessaire dans certains cas de l’expliciter.

Au niveau des actions possible, nous trouvons entre autres :

  • DUNNO: On ne fait rien (sort du contrôle en cours et permet d’éviter un éventuel match avec une règle plus bas…)
  • HOLD: le mail reste dans la queue de Postfix.
  • REDIRECT: redirection du mail vers une autre adresse.
  • etc…

Plus de détails ici : http://www.postfix.org/access.5.html

Si vous utilisez des fichiers statiques, après chaque modification, il faudra invoquer :

# postmap /etc/postfix/nomdufichier

Et pour rappel, vu notre configuration actuelle, ces quatre contrôles se font dans un sens (mail entrant) et dans l’autre (mail sortant).

Chacun de ces contrôles prendra place ensuite dans son bloc smtpd_*_restrictions correspondant.

A – check_client_access

Ici, on peut autoriser ou interdire des IPs ou des domaines spécifiques.

Exemple :

111.222.111.222 REJECT
domaineabloquer.com REJECT

Et cela se place de la sorte :

smtpd_client_restrictions =
    check_client_access hash:/etc/postfix/acces_client,
    [...]

Pour filtrer des lourds (spammeurs, bots, etc…), ce n’est pas forcement la meilleure solution. D’une, il faut que la la liste d’accès soit maintenue à jour, et c’est alors un travail quotidien, ou presque…

Seconde « limitation », même en cas de Reject, la session SMTP ira jusqu’au RCPT ou bien sur, elle sera terminée, mais on a gaspillé de la ressource à aller si loin.

On peut demander à Postfix d’arrêter la communication dès qu’une restriction s’applique (en mettant l’option  smtpd_delay_reject = no) mais pour trouver un éventuel soucis par la suite, ce peut être gênant. Autre problématique, certains clients gèrent mal une connexion coupée de la sorte…

Je conseille donc de laisser comme c’est par défaut.

Et donc pour bloquer des IPS spécifiques, je passe soit par mon firewall, soit par Postscreen (qu’on verra plus tard).

B – check_helo_access

Ici est effectué un contrôle sur le helo. Comme pour le client, c’est vite compliqué de maintenir quelque chose à jour.

Cependant, on peut quand même effectuer un petit contrôle de routine pour éviter le helo qui serait le notre, ça ne mange pas de pain…

smtpd_helo_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    check_helo_access ldap:/etc/postfix/ldap/check_helo_domains_reject.cf,
    [...]

Et le fichier /etc/postfix/ldap/check_helo_domains_reject.cf correspondant :

server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=mail,dc=debugo,dc=fr
scope = sub

query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))
result_attribute = maildomain
result_filter = REJECT Menteur

Rien de sorcier…

On pense à recharger Postfix :

# postfix reload

C – check_recipient_access

La, on peut contrôler le destinataire :

Par exemple :

toto@domaine.fr REJECT

Pour bloquer les mails destiné a mon utilisateur toto. Oui, c’est pas franchement utile…

Ou bien encore :

adresseextene@gmail.com REJECT

Pour bloquer les mails à destination de cette adresse. L’intérêt la aussi, dans notre cas de figure, est faible, mais ça existe et ça peut servir.

D – check_sender_access

Ici, on va effectuer un contrôle au niveau de l’expéditeur et on va revenir  sur l’antiforge dont je parlais avant pour s’intéresser à un cas que je n’ai pas traité :

Imaginons un serveur SMTP qui nous envoie un mail avec comme FROM TO un mail du genre userbidon@domaine1.fr, la bal n’appartenant à personne, le reject_sender_login_mismatch qu’on a vu plus haut ne bloquera rien,  le mail passera.

On va donc y remédier. L’idée étant d’autoriser en FROM TO nos mails qui existent et de rejeter le reste.

Dans le bloc smtpd_sender_resctrictions, nos usagers sont déjà autorisés via permit_sasl_authenticated, on va donc ajouter juste après la restriction pour nos domaines.

On aurait alors besoin d’un fichier ressemblant à ça :

@domaine1.fr      REJECT
@domaine2.fr    REJECT

Et comme on a le Ldap pour alimenter cela, on va donc passer  par un fichier nommé /etc/postfix/ldap/check_sender_domains_reject.cf :

server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=mail,dc=debugo,dc=fr
scope = sub

query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))
result_attribute = maildomain
result_filter = REJECT Ho le vilain....

Et cela se place de la sorte  dans le fichier /etc/postfix/main.cf :

smtpd_sender_restrictions =
    reject_sender_login_mismatch,
    permit_mynetworks,
    permit_sasl_authenticated,
    check_sender_access ldap://etc/postfix/ldap/check_sender_domains_reject.cf,
    [...]

L’ordre est important. Si le check_sender_access est positionné avant le permit_sasl_authenticated, nos propres utilisateurs ne pourraient pas envoyer de mails.

On recharge :

# postfix reload

Et voila l’antiforge amélioré.

 

IV – Les « Header Checks »

Dernière série de contrôle que l’on peut effectuer ou l’on va regarder un peu plus profondément dans le mail.

Postfix nous propose plusieurs types de contrôles sur les headers :

  • header_check : contrôle dans le header (format ASCII)
  • mime_header_check : contrôle dans le header (format MIME)
  • body_header_check : contrôle dans corps.
  • etc…

Plus de détails ici : http://www.postfix.org/header_checks.5.html

Pour les utiliser, il faut tout d’abord installer le module PCRE de Postfix :

# apt install postfix-pcre

On recharge Postfix :

# postfix reload

A partir de maintenant, on va pouvoir inspecter, via des REGEX, ce qu’il y a dans les mails.

La syntaxe est la suivante :

/^Subject:.*viagra*/ REJECT Pas besoin, merci
/^From: *toto*/    REJECT On connait la blague

De mon avis et expérience, pour filtrer le spam, ce n’est plus vraiment la meilleure solution sauf cas particulier. Compliqué de maintenir un truc à jour, risque d’un regex un peu foireux qui pourrait être trop restrictif…

Pour information, il est possible de tester vos regex de la sorte :

# postmap -q "Subject: viagra" pcre:/etc/postfix/header_checks

Cela doit vous renvoyer la règle qui s’applique.

Si vous voulez tester avec un mail sauvegardé dans un fichier :

# postmap -q - pcre:/etc/postfix/header_checks < mail.txt

Le second – après le -q est important.

 

Donc pour le traitement du spam, on fait mieux, cependant, je me sers du header_check pour deux choses.

Créons  d’abord le répertoire qui va accueillir nos fichiers :

# mkdir /etc/postfix/check/

A – Filtrage des fichiers à risque

Au niveau filtrage en entrée, pour la démonstration, je ne montre qu’un exemple simple. A vous après de faire vos propres règles.

Créons un fichier /etc/postfix/check/header_checks_in avec ce qui suit :

/^name=[^>]*\.(com|vbs|js|exe|bat|cmd|scr|hlp|pif|dll)/ PREPEND X-DEBUGO: WARN
/^Content-(Disposition|Type):\s+.+?(?:file)?name="?.+?\.(yo|com|vbs|js|exe|bat|cmd|scr|hlp|pif|dll)\b/ PREPEND X-DEBUGO: WARN

Ici, un header perso X-DEBUGO: WARN est ajouté si le mail contient un fichier avec les extensions bat, exe, com, etc… Celui ci pourra me servir à effectuer un filtre avec Sieve.

Au niveau des actions, on retrouve peu ou prou ce qu’on avait pour les contrôles d’accès. On peut donc aussi utiliser REJECT pour le rejeter, REDIRECT xxx@domaine1.fr , etc…

Voila pour les contrôles en entrée.

B – Supprimer les informations sensibles

L’autre utilité est de pouvoir masquer certaines informations de vos mails sortants, tel que votre IP d’envoi, votre client mail… Par défaut, les headers ajoutés par votre client de messagerie sont un peu trop causant…

Si on regarde ces fameux headers d’un mail qui partirait de chez vous vers un destinataire externe, le premier Received ressemblerait à cela :

Received: from [monip] (monreverse[monip])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
        (No client certificate requested)
	by mail.domaine1.fr (Postfix) with ESMTPSA id 3AB4D22938
	for <destinataire@destination.com>; Mon,  21 Jul 1969 02:56:20 +0000 (UTC)

Au passage, pour lire les headers d’un mail, il faut commencer par le bas. Le premier Received que l’on voit en haut est en fait le dernier SMTP rencontré, celui du destinataire.

Et donc notre destinataire, s’il est un peu curieux, peut connaitre notre IP. Puis s’il descend un peu, il en apprendra davantage sur votre OS, etc…

Hum, ce n’est pas terrible…

Allez, nettoyons tout cela !

Dans un fichier /etc/postfix/check/header_checks_out :

/^\s*Received: from \S+ \(\S+ \[\S+\]\)(.*)/ REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])$1
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^Mime-Version:/ IGNORE
/^User-Agent:/ IGNORE

Au passage, on rencontre souvent sur internet ce regex :

/^Received:.*with ESMTPSA/ IGNORE

En lieu et place de celui que je vous ai indiqué. Celui ci est un peu trop violent à mon gout, vu qu’il supprime complétement le Received from vous concernant. Il peut toujours être utile d’indiquer que vous étiez en TLS, le serveur qui a reçu le mail, etc… Je préfère donc juste masquer l’IP d’origine.

C – Oui mais…

Si on indique ces checks dans le main.cf avec :

header_checks = pcre:/etc/postfix/check/header_checks_in,pcre:/etc/postfix/check/header_checks_out
mime_header_checks = pcre:/etc/postfix/check/header_checks_in,pcre:/etc/postfix/check/header_checks_out

Ils vont se faire sur les mails qui entrent et qui sortent. Et on ne veut pas effacer les headers des mails qui nous arrivent… ni ajouter un éventuel header au mail que l’on envoie.

Que faire…

Il existe la directive smtp_header_check qui s’applique uniquement pour les mails sortants, mais ça ne règle pas notre problème, on veut deux jeux distincts (puis par la suite, on voudra encore affiner…)

Pour info, ces checks sont exécutés par le process cleanup, la solution élégante est d’en faire deux « sous process ». Chacun en charge d’un traitement, affecté comme il faut.

Pour se faire, c’est assez simple :

On édite le fichier /etc/postfix/master.cf pour y ajouter pour chaque service un nouveau service cleanup :

smtp       pass   -   -   y   -   -   smtpd
  -o cleanup_service_name=subcleanin
[...]
submission inet   n   -   y   -   -   smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o cleanup_service_name=subcleanout
smtps      inet   n   -   y   -   -   smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o cleanup_service_name=subcleanout

Et plus bas, en dessous du cleanup existant, on ajoute :

cleanup     unix   n   -   y   -   0   cleanup
subcleanout unix   n   -   -   -   0   cleanup
  -o header_checks=pcre:/etc/postfix/check/header_checks_out
  -o mime_header_checks=pcre:/etc/postfix/check/header_checks_out
subcleanin  unix   n   -   -   -   0   cleanup
  -o header_checks=pcre:/etc/postfix/check/header_checks_in
  -o mime_header_checks=pcre:/etc/postfix/check/header_checks_in

Précisez bien header_checks et mime_header_checks : les headers pouvant être dans le format MIME ou ASCII, il est important de bien traiter les deux cas.

On recharge Postfix :

# postfix reload

Et voila !

V – Conclusion

Voila qui termine cette première  partie sur l’optimisation de Postfix.

J’ai ai profité pour vous montrer quelques astuces et vous initier à la toute puissance de Postfix.

Je vous invite bien évidement à consulter la doc officielle qui vous permettra de trouver réponses à vos cas particuliers. Bien sur, vous pouvez aussi poser vos questions ici même dans les commentaires.

Allez,  courage, on a bientôt terminé ! Dans la partie V, nous allons encore ajouter deux petits modules à Postfix : Policy Spf et Postscreen.

2 réflexions sur « Tuto Messagerie, partie IV : Optimisation de Postfix »

  1. Hello,

    En supprimant le MIME avec les header checks, on se prend pas du coup un gros malus à l’antispam ? En utilisant cette option, j’ai des points de spam qui apparaissent :

    MISSING_MIME_VERSION(2.00)[];
    MIME_HEADER_CTYPE_ONLY(2.00)[];

    Que je n’ai pas sans.

  2. Ha mince, j’étais passé à côté de ta remarque.
    C’est pas faux, et puis le supprimer n’est pas non plus le truc le plus important.

    Du coup, celui ci, on peut laisser.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *