Introduction

Dans la lutte contre le SPAM, j'ai déjà adopté certaines mesures comme le greylisting. C'est efficace même si cela n'est pas parfait. Néanmoins, il y a un élément dont je ne dispose toujours pas. En effet, je ne sais pas qui est le vendu de l'histoire...

Car régulièrement, au gré de ma vie numérique connectée, je dois laisser trainer mon adresse de courrier électronique. Bien entendu, même si les sites qui récupèrent cette information s'engagent tous à ne pas la refourguer à d'autres compagnons, mon niveau de confiance est proche de l'ensemble vide. Mais alors, que faire ?

Les alias délimités viennent à notre rescousse

Un moyen simple consiste à utiliser ce que j'appelle des alias délimités. C'est sans doute une mauvaise traduction de l'option 'recipient delimiter' du MTA Postfix. Cela consiste en l'utilisation d'un caractère de délimitation au sein d'une adresse de courrier électronique.

Concrètement, cela prend la forme suivante: si vous avez une adresse de courrier en toto@mondomaine.example, vous pouvez utilisez aussi une adresse du type toto_cequevousvoulez@mondomaine.example. Elle sera acceptée par votre MTA et le message sera routé vers toto@mondomaine.example.

L'astuce consiste à utiliser un délimiteur (ici, c'est '' mais ça peut être ce qu'on veut) en suffixe d'une adresse autorisée, c'est-à-dire qui existe réellement sur votre serveur. Ainsi, lorsque vous confiez votre adresse à un site marchand qui en a vraiment besoin, vous pouvez simplement utiliser totonomdumarchand@mondomaine.example comme adresse. Elle sera reconnue par votre MTA et vous recevrez du courrier électronique directement à votre adresse principale, sans aucune configuration.

L'intérêt de cette méthode consiste à fournir uniquement des adresses personnalisées pour chaque site sur lequel vous avez un compte. De cette manière, si vous récupérez du spam, il vous suffit d'afficher l'adresse d'origine (elle est présente dans les en-têtes et nombreux sont les MUA qui l'affichent (souvent pas par défaut).

Ainsi, vous saurez quel site a proprement revendu ou refourgué votre précieuse adresse. Google implémente cette astuce avec le délimiteur '+'.

Après cet intermède de haut niveau, passons à la mise en oeuvre...

Quelques rappels sur la configuration d'Exim4 sous Debian

Bon, ce qui est bien avec Debian et aussi avec Exim, c'est qu'une fois que la configuration est correctement implémentée, on n'a plus à y toucher pendant de nombreuses années.

Concrètement, le vrai fichier de configuration utilisé par Exim est situé dans /var/lib/exim4/config.autogenerated. Ce fichier est, comme son nom l'indique, généré par un programme dédié nommé update-exim4.conf (oui, je sais, un exécutable avec un .conf dedans, c'est peu courant). Ce dernier utilise la configuration éclatée située dans /etc/exim4/conf.d ainsi que le fichier de macros /etc/exim4/update-exim4.conf.conf (ça fait beaucoup de .conf non ?).

Pour modifier la configuration d'Exim, vous devez donc modifier des choses dans les fichiers situés dans /etc/exim4/conf.d puis lancer update-exim4.conf et relancer votre service exim4 (systemctl restart exim4).

Implémentation des alias délimités dans Exim4

Je ne vais pas vous ré-expliquer les principes d'Exim, il me faudrait un livre entier. Vous pouvez néanmoins vous réferrer à la documentation officielle qui est pour le coup, complète.

Comme tout ce qui a trait à la délivrance de courrier électronique dans Exim, nous allons simplement créer un router spécifique qui se charge de vérifier la présence du délimiteur en suffixe, de l'enlever avec tout le reste de l'adresse initiale et de balancer le message vers un autre routeur, chargé lui des adresses "officielles".

Je vous invite à créer un fichier nommé /etc/exim4/conf.d/router/310_recipient_delimiter (le nom est important pour l'ordre d'enchaînement des routers) avec le contenu suivant:

### router/300_recipient_delimiter
##################################

# Ce router gère la redirection vers les adresses dynamiques, définies
# avec un délimiteur. ex: toto__whatever est redirigé vers toto

recipient_delimiter:
  debug_print = "R: recipient_delimiter for $local_part@$domain"
  driver = redirect
  domains = +local_domains
  local_part_suffix =  __* : ..*
  data =  ${quote_local_part:$local_part}@$domain
  redirect_router = system_aliases

Voici les quelques explications indispensables à la compréhension de ce que nous faisons.

D'abord, nous créons un router spécifique. Il est nommé recipient_delimiter. Vous pouvez mettre ce que vous voulez comme nom mais, pour rester conforme à ce qui existe dans la littérature des MTA, j'utilise le terme recipient delimiter.

debug_print est une instruction qui imprime un message lorsqu'on est dans le mode debug d'Exim (cf plus bas). Il affiche une chaîne de caractères qui nous permet de prendre connaissance des variables local_part et domain. Ces variables contiennent respectivement la partie initiale de l'adresse en cours de traitement (toto) et le domaine traité. Le fait de mettre $ devant un nom de variable permet d'afficher son contenu (c'est $ qui permet le développement du contenu de la variable).

driver = redirect indique que ce router est de type redirect. C'est le router d'Exim qui permet la redirection de message vers d'autres routers. C'est pleinement ce que nous cherchons à faire: rediriger toto__whatever vers toto qui sera gérée par un autre router (system_aliases dans notre cas).

domains est la liste des domaines acceptés par ce router. Dans notre cas, il s'agit des domaines du système, stocké dans la variable local_domains. En fait cette variable est une liste nommée, on utilise le caractère + pour indiquer qu'on souhaite utiliser le contenu de la liste et non la chaîne de caractères en direct.

local_part_suffix est une condition pour que le router capture le message. Concrètement, si le contenu de cette condition est vérifié, alors le message est géré par notre router recipient_delimiter. Si ce n'est pas le cas, alors le message n'est pas traité par ce router (et il y a de fortes chances pour qu'à la fin, il soit rejeté). La chaîne de correspondance utilise la syntaxe d'Exim des listes. Concrètement, le suffixe cherché est du type __* ou ..* qui traite donc les adresses du type toto__whatever ou toto..whatever (* correspond à n'importe quel caractère). Attention, cette option est plus puissante qu'on ne peut le penser. En effet, le simple fait de déclarer un suffixe de partie locale d'adresse suffit à réduire la partie locale de l'adresse à la partie avant le suffixe.

data est une option de configuration des routers de type redirect. Elle indique, dans la syntaxe Exim, un moyen de trouver l'adresse réelle (toto@mondomaine.example) à partir de l'adresse initiale (toto__whatever@mondomaine.example). quote_local_part est un opérateur qui permet de mettre entre quotes la partie locale de l'adresse. Il faut l'utiliser chaque fois qu'on travaille sur la partie locale de l'adresse. Il permet de se conformer à la RFC 2822 qui gère la syntaxe du courrier électronique. On utilise ici local_part directement car local_part_suffix a déjà fait le travail de séparation pour nous.

Enfin, redirect_router est une autre option des routers de type redirect qui permet d'indiquer vers quel autre router ou balance le message qui correspond au suffixe et qui contiendra l'adresse réelle trouvée. Dans notre cas, il s'agit de system_aliases qui gère les alias systèmes et qui est le router que j'utilise pour mes comptes de messagerie configurés. Ce dernier gère la suite comme un grand.

Attention, j'utilise un transport assez simple (celui qui distribue le courrier dans un répertoire utilisateur en direct) mais si vous utilisez un transport plus élaboré qui utilise un service externe, il faudra sans doute configurer le service externe pour prendre en compte aussi l'adresse originelle qui est transmise dans les en-tête du message.

Tester notre configuration

Après avoir appliqué votre configuration, vous pouvez la tester en utilisant l'option -bt du binaire exim, de la manière suivante:

# exim4 -bt toto__nimportequoi
R: recipient_delimiter for toto__nimportequoi@mondomaine.example
R: system_aliases for toto__nimportequoi@mondomaine.example
R: system_aliases for moi@mondomaine.example
R: userforward for moio@mondomaine.example
R: procmail for moi@mondomaine.example
R: maildrop for moi@mondomaine.example
R: lowuid_aliases for moi@mondomaine.example (UID 1053)
R: local_user for moi@mondomaine.example
moi@medspx.fr
    <-- toto@mondomaine.example
    <-- toto__nimportequoi@mondomaine.example
  router = local_user, transport = maildir_home

Ici, on voit que toto__nimportequoi est transformé en toto puis en moi (la véritable adresse car toto est aussi un alias mais non dymanique, déclaré dans /etc/aliases)

En cas de problème, vous aurez probablement un message du type:

R: system_aliases for toto__nimportequoi@mondomaine.example
toto__nimportequoi@mondomaine.example is undeliverable: Unrouteable address

Afficher la source dans Roundcube

Dans Roundcube, l'adresse originelle n'est pas affichée par défaut, vous devrez activer la colonne À pour l'afficher dans la liste des courriels entrants.

Conclusions

Avec ce routeur, vous avez une infinité d'adresses de courrier électronique à votre disposition pour lutter contre le SPAM en sachant qui vous a vendu.

Maintenant, cet article ne parle pas de la contre-offensive possible qui peut prendre une forme légale (si vous avez envie de prendre du temps pour ça), une redirection vers du SPAM par défaut de cette adresse une fois qu'elle a été revendue ou encore plus radical, un bannissement de l'adresse au niveau du serveur.

Références

Posted sam. 13 janv. 2018 17:37:07 Tags:

Introduction

Ah, le courrier électronique, son utilisation est simple et quasi-universelle mais il existe tellement d'options et de fonctionnalités à ajouter à ce monument d'Internet qu'on oublie à quel point que faire fonctionner une plate-forme de courrier électronique requière de sérieuses compétences.

Aujourd'hui, nous allons mettre en place une technologie de filtrage au niveau du serveur pour filtrer les courriers en amont, en fonction des besoins de chaque utilisateur. Mission pas facile mais que nous allons néanmoins relever grâce à la technologie Sieve.

Récapitulatif de ce qu'il faut mettre en place

Exim4 propose la gestion de Sieve mais à un niveau assez bas: un fichier de filtre doit être déposé dans le répertoire de l'utilisateur pour qu'Exim le gère correctement. Mais, je pense que cette fonctionnalité n'est pas assez user-friendly.

On peut également implémenter Sieve du côté du serveur IMAP mais cela implique d'utiliser un service de délivrance de courrier et que ce service soit assuré par le serveur IMAP lui même. Dans le monde du courrier électronique, il existe deux grands types de service de délivrance de courrier "IMAP": LDA et LMTP. Nous retiendrons LMTP qui est plus "moderne" et surtout mieux implémenté dans Dovecot que LDA (qui repose sur un binaire externe).

Bien entendu, il faut dire au MTA qu'il doit utiliser ce service LMTP, il faudra donc modifier la configuration d'Exim4.

Une fois LMTP activé, on pourra mettre en place la gestion de Sieve dans Dovecot. Néanmoins, le problème sera identique à celui d'Exim: il reste à fabriquer les fichiers de filtres et à les déposer sur le serveur...

Heureusement, il existe un service dédiéà ça: ManageSieve. Il en existe une implémentation dans Dovecot que nous allons installer et configurer.

Enfin, si on souhaite que les filtres soient personnalisés, il reste à offrir une interface permettant de les déposer depuis le Webmail. C'est ce qui est permis par l'extensions ManageSieve de Roundcube et que nous allons également mettre en place.

On le voit, il y a du boulot en perspective... Commençons dès à présent et pas à pas !

Installation de LMTP pour Dovecot

Avant de commencer, il nous faut un serveur LMTP. Il existe une extension Dovecot qui fait très bien ce travail.

Installation

Sous Debian, c'est assez simple:

# apt install dovecot-lmtpd

Le paquet fait moins d'1Mo, pas de problème sur un PlugComputer.

Configuration

Pour configurer correctement ce mode de transport du courrier électronique, il ne faut pas oublier quelle est notre cible. En effet, nous voulons qu'Exim utilise le service LMTP pour transmettre les courriers électroniques qui seront ensuite gérés par Dovecot, lequel appliquera alors les filtres Sieve.

L'activation du protocole LMTP se fait dans le fichier maître de configuration, à savoir /etc/dovecot/conf.d/10-master.conf:

# Configuration du service LMTP
service lmtp {
  # On active le protocole LMTP sur une socket UNIX
  unix_listener lmtp {
    #mode = 0666
  }

  # On désactive le protocole LMTP par TCP
  #inet_listener lmtp {
    # Avoid making LMTP visible for the entire internet
    #address =
    #port = 
  #}
  # On va réserver 2 processus pour LMTP
  process_min_avail = 2

  # On veut que LMTP loggue les erreurs
  executable = lmtp -L
}

La configuration fine du protocole LMTP se fait dans le fichier /etc/dovecot/conf.d/20-ltmtp.conf:

##
## Configuration LMTP
##

# Pas de proxy LMTP
lmtp_proxy = no

# Pour les alias délimités, on va poser les courriels dans la 
# boîte finale et non dans la boîte aliasée.
lmtp_save_to_detail_mailbox = no

# Pas de vérification de quota
lmtp_rcpt_check_quota = no

# Toujours écrire dans la boîte aux lettres finale
# et non dans la boîte aliasée.
lmtp_hdr_delivery_address = final

protocol lmtp {
  # Les extensions gérées par lmtp
  mail_plugins = $mail_plugins
  # Le fichier de log spécifique
  info_log_path = /var/log/dovecot/dovecot-lmtp.log
  # Il faut enlever la partie du domaine pour nommer nos utilisateurs
  auth_username_format = %n
}

Intégration de LMTP dans Exim4

Maintenant que nous disposons d'un service LMTP, il reste à le faire utiliser par Exim. Par défaut, au moins, dans ma configuration simple d'Exim, j'utilise un mode de délivrance de courrier assez basique: Exim pose le message sous forme de fichier dans une arborescence Maildir. Il s'agit du transport maldir_home.

Pour mettre en place LMTP dans Exim, vous devrez configurer un router dédié ainsi qu'un transport vers le service. Nous allons placer ce transport dans le fichier /etc/exim4/conf.d/tranport/30_exim4-config_dovecot_lmtp:

dovecot_lmtp:
        driver = lmtp
        socket = /var/run/dovecot/lmtp
        #maximum number of deliveries per batch, default 1
        batch_max = 200
        # on supprime les suffixes/préfixes
        rcpt_include_affixes = false

Il reste ensuite à utiliser ce transport. Le moyen le plus simple consiste à utiliser le fichier de macros fourni par Debian: /etc/exim4/update-exim4.conf.conf et de modifier la variable dc_localdelivery qui permet d'indiquer le transport servant à la délivrance locale des courriels. Donc mon cas, j'ai juste modifié la valeur à :

dc_localdelivery='dovecot_lmtp'

Ensuite, vous pouvez redémarrer Exim (via systemctl bien-sûr) et faire un test d'adresse (via l'option -bt) pour lire le transport qui sera utilisé.

Mise en place de Sieve dans Dovecot

Installation

Ok, LMTP est en place et fonctionnel, il nous reste à nous occuper de la configuration de Sieve dans Dovecot. Il faut juste installer le paquet dovecot-sieve et son pendant administratif dovecot-managesieved:

# apt install dovecot-sieve dovecot-managesieved

Configuration

La configuration est assez simple. Il faut juste activer le module dans le transport adapté (ce sera LMTP pour nous) et configurer le fichier de l'extension.

Vous devrez d'abord activer le module sieve de LMTP. L'action se trouve dans la conf de LMTP, /etc/dovecot/conf.d/20-lmtp.conf:

protocol lmtp {                                                                                                                                             
  mail_plugins = $mail_plugins sieve                                                                                                                        
  ...
}

Ensuite, l'action se déroule dans /etc/dovecot/conf.d/90-sieve.conf. Je dirais que la configuration par défaut fait très bien le job dans la majorité des cas. La ligne la plus importante étant sans doute celle qui indique l'emplacement du répertoire de filtre et le fichier par défaut:

sieve = file:~/sieve;active=~/.dovecot.sieve

Cette ligne indique que le répertoire des filtres sieve sera ~/sieve et que le filtre par défaut à utiliser sera le lien symbolique ~/.dovecot.sieve.

A ce stade, la configuration est totalement compatible avec celle de l'interface ManageSieve de Roundcube donc, pour 90% des cas, ça ne sert à rien d'aller plus loin.

Pour plus d'informations, je vous invite à lire la page de référence.

Mise en place de ManageSieve dans Dovecot

Il reste maintenant à configurer ManageSieve dans Dovecot. Nous souhaitons activer le service uniquement sur localhost car l'accès à la configuration se fera via Roundcube qui est sur la même machine, donc pas besoin de présenter un port sur une IP publique.

Vous devez simplement renseigner le fichier de configuration /etc/dovecot/conf.d/20-managesieve.conf avec le contenu suivant:

##                                                                                 
## Configuration ManageSieve pour Dovecot                                          
##                                                                                 

# Nous activons ManageSieve                                                        
protocols = $protocols sieve

# Configuration de la connection au service                                        
service managesieve-login {
  inet_listener sieve {
    address = ::1, 127.0.0.1
    port = 4190
  }

  #inet_listener sieve_deprecated {                                                
  #  port = 2000                                                                   
  #}                                                                               

  # Number of connections to handle before starting a new
  process. Typically       
  # the only useful values are 0 (unlimited) or 1. 1 is more secure,
  but 0         
  # is faster. <doc/wiki/LoginProcess.txt>                                         
  #service_count = 1                                                               

  # Number of processes to always keep waiting for more connections.               
  #process_min_avail = 0                                                           

  # If you set service_count=0, you probably need to grow this.                    
  #vsz_limit = 64M                                                                 
}

#service managesieve {                                                             
  # Max. number of ManageSieve processes (connections)                             
  #process_limit = 1024                                                            
#}                                                                                 

# Service configuration                                                            

protocol sieve {
  # Maximum ManageSieve command line length in bytes. ManageSieve
  usually does     
  # not involve overly long command lines, so this setting will not
  normally       
  # need adjustment                                                                
  #managesieve_max_line_length = 65536                                             

  # Maximum number of ManageSieve connections allowed for a user from
  each IP      
  # address.                                                                       
  # NOTE: The username is compared case-sensitively.                               
  #mail_max_userip_connections = 10

  # Space separated list of plugins to load (none known to be useful
  so far).      
  # Do NOT try to load IMAP plugins here.                                          
  #mail_plugins =                                                                  

  # MANAGESIEVE logout format string:                                              
  #  %i - total number of bytes read from client                                   
  #  %o - total number of bytes sent to client                                     
  #managesieve_logout_format = bytes=%i/%o                                         

  # To fool ManageSieve clients that are focused on CMU's timesieved
  you can       
  # specify the IMPLEMENTATION capability that Dovecot reports to
  clients.         
  # For example: 'Cyrus timsieved v2.2.13'                                         
  #managesieve_implementation_string = Dovecot Pigeonhole                          

  # Explicitly specify the SIEVE and NOTIFY capability reported by the
  server      
  # before login. If left unassigned these will be reported
  dynamically            
  # according to what the Sieve interpreter supports by default (after
  login       
  # this may differ depending on the user).                                        
  #managesieve_sieve_capability =                                                  
  #managesieve_notify_capability =                                                 

  # The maximum number of compile errors that are returned to the
  client upon      
  # script upload or script verification.                                          
  #managesieve_max_compile_errors = 5                                              

  # Refer to 90-sieve.conf for script quota configuration and
  configuration of     
  # Sieve execution limits.                                                        
}

Mise en place de ManageSieve dans Roundcube

Maintenant que nous avons configuré l'infrastructure de bas niveau, il reste à configurer Roundcube. Ce dernier propose une extension bien nommée puisqu'elle s'appelle ManageSieve.

Installation

Vous devez vous assurer que vous disposez du paquet roundcube-plugins pour disposer de cette fonctionnalité:

# apt install roundcube-plugins

Mise en oeuvre

Vous devez activer l'extension en vous assurant qu'elle soit dans les extensions autorisées de Roundcube. Pour cela, allez modifier le fichier /etc/roundcube/config.inc.php:

// List of active plugins (in plugins/ directory)                                  
$config['plugins'] = array(
'archive',
'calendar',
'carddav',
'emoticons',
'managesieve',
'zipdownload',
'enigma'
);

Il reste ensuite à paramétrer finement l'extension. On peut le faire en ajoutant le fichier /etc/roundcube/plugins/managesieve/config.inc.php avec le contenu suivant:

<?php
// Le port managesieve utilisé. Ce sera 4190, le port réservé.                     
$config['managesieve_port'] = 4190;

// L'emplacement du serveur. Dans notre configuration, ce sera                     
// localhost car Roundcube est sur la même bécane.                                 
$config['managesieve_host'] = 'localhost';

// Méthode d'authentification utilisée.                                            
// Nous n'en employons aucune car nous sommes sur la même bécane.                  
$config['managesieve_auth_type'] = null;

// Option pour utiliser un compte alternatif pour
l\'authentification.             
// Ici, nous n'utilisons pas cette option.                                         
$config['managesieve_auth_cid'] = null;
$config['managesieve_auth_pw'] = null;

// On s'en fout d'utiliser TLS pour se connecter.                                  
$config['managesieve_usetls'] = false;
$config['managesieve_conn_options'] = null;

// default contents of filters script (eg. default spam filter)                    
$config['managesieve_default'] = '/etc/dovecot/sieve/global';

// Nom du script utilisé lorsque l'utilisateur n'a rien configuré.                 
$config['managesieve_script_name'] = 'managesieve';

// On est en 2018, UTF-8 est partout !                                             
$config['managesieve_mbox_encoding'] = 'UTF-8';

// Option pour Dovecot.                                                            
$config['managesieve_replace_delimiter'] = '';

// Ici, on peut désactiver des plugins Sieve.                                      
// Ce ne sera pas le cas sur notre configuration.                                  
$config['managesieve_disabled_extensions'] = array();

// Nous ne sommes pas en mode Debug.                                               
$config['managesieve_debug'] = false;

// Nous désactivons les options spécifiques de Kolab.                              
$config['managesieve_kolab_master'] = false;

// Extension des fichiers Sieve. Ce sera .sieve pour se conformer à                
// Dovecot.                                                                        
$config['managesieve_filename_extension'] = '.sieve';

// Une liste de noms de scripts Sieve non présentés à l\'utilisateur.
// Dans notre cas, nous n'en avons aucun.                                          
$config['managesieve_filename_exceptions'] = array();

// Une liste de domaine fermée pour contraindre les redirections.                  
// Vers d'autres domaines de courriel.                                             
$config['managesieve_domains'] = array();

// Options pour la gestion des absences.                                           
// Nous activons l'interface de gestion d'absences.                                
$config['managesieve_vacation'] = 1;

// Durée par défaut de l'absence en jours.                                         
$config['managesieve_vacation_interval'] = 7;

// Pré-remplissage de l'adresse utilisée pour la réponse.                          
$config['managesieve_vacation_addresses_init'] = true;

// Méthodes utilisées pour renvoyer le message d'absence.                          
$config['managesieve_notify_methods'] = array('mailto');
?>

Un exemple de filtre

Ce script permet de détecter ce qui vient d'une mailing-list et de le balancer dans une boîte dédiée.

# rule:[QGIS developper mailing list]                                                                                                                       
if anyof (header :contains "from" "qgis-developer@lists.osgeo.org", header :contains "return-path" "qgis-developer@lists.osgeo.org")
{                                                                                                                                
        fileinto "QGis-dev";
}

Mais, le plus simple est d'utiliser l'interface de Rouncube, c'est plus user-friendly !

Conclusions

Bon, c'était un poil complexe quand même ! Il y en a de partout et nous avons bien travaillé quand même. Faisons le bilan:

  • Nous avons modifié la configuration du MTA (Exim4) pour lui faire utiliser un transport dédié.
  • Nous avons mis en place un service LMTP via Dovecot.
  • Nous avons intégré et configuré la gestion de Sieve dans Dovecot.
  • Nous avons intégré et configuré un service ManageSieve via Dovecot.
  • Nous avons installé une extension de Rouncube permettant à l'utilisateur final de gérer ses propres scripts.

Pas simple effectivement pour une fonctionnalité qui peut sembler assez basique. Mais c'est ainsi: le courrier électronique applique à fond le principe UNIX: une fonctionnalité = un outil dédié. C'est comme ça et ça démontre qu'il sera toujours complexe d'administrer une plate-forme de courrier électronique. Le niveau de compétences à avoir est quasi identique pour une plate-forme mono-utilisateur que pour une plate-forme d'entreprise.

Voilà de quoi ajouter à votre CV qui ne pourra que satisfaire vos futurs recruteurs...

Posted dim. 14 janv. 2018 20:25:35 Tags: