Nous avons parlé à plusieurs reprises de la mise en place de SSL/TLS dans différentes situations (dans « il était une fois internet« , sur jeveuxhttps.fr, pour AlternC, ou plus récemment sur la faille POODLE). Autant il est facile d’enlever le protocole SSLv3 des serveurs web (seul le navigateur obsolète Internet Explorer 6 ne pourra plus se connecter), autant il peut être utile de se poser la question pour les mails.
Une des solutions possible consiste à copier automatiquement tous les mails dans un répertoire indépendant, prendre les informations qui nous intéressent dans les en-têtes, puis effacer ces copies. On peut ainsi récupérer ce type de ligne (issu de l’en-tête Received: ajouté par Postfix) qui nous indique le chiffrement de la connexion :
(using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))
La mise en place d’un processus de collecte de statistiques est réellement simple :
- créer une nouvelle adresse mail en pop/imap dédiée à cette tâche
- modifier le fichier /etc/postfix/main.cf pour y ajouter les 2 lignes suivantes :
always_bcc = L_ADRESSE_EMAIL_DEDIEE smtpd_sasl_authenticated_header = yes
Puis on recharge Postfix via la commande service postfix reload . Après avoir vérifié que tout fonctionne bien (par exemple avec /var/log/mail.log ), on passe à la suite.
- vous pouvez copier le script ci-desssous dans un fichier que l’on appellera ssl.php .
#!/usr/bin/env php <?php // postfix must have always_bcc = this mailbox // and smtpd_sasl_authenticated_header = yes // you can cronify this as follow: // * * * * * root php /root/ssl.php >>/var/log/ssl.log // Set this to be the dedicated mailbox's root Maildir: $ROOT="/var/mail/alternc/t/tls_octopuce.fr/Maildir"; $message_list=array(); $hostname=trim(file_get_contents("/etc/mailname")); $d=opendir($ROOT."/cur"); while (($c=readdir($d))!==false) { if (is_file($ROOT."/cur/".$c)) { addmail($ROOT."/cur/".$c); } } closedir($d); $d=opendir($ROOT."/new"); while (($c=readdir($d))!==false) { if (is_file($ROOT."/new/".$c)) { addmail($ROOT."/new/".$c); } } closedir($d); // This function get a maildir email and extract the relevent informations from it. // then it DELETES this email! function addmail($file) { global $message_list,$hostname; $f=fopen($file,"rb"); $status=0; $received_list=array(); $messageid=""; // automaton having status: 0=in headers 1=in a received: header 2=had a message-id header while ($s=fgets($f,1024)) { if (!trim($s)) { break; // we leave the header part, quit } if ($status==1) { if (substr($s,0,1)==" " || substr($s,0,1)==chr(9)) { $received.=" ".trim($s); } else { $received_list[]=$received; $received=""; $status=0; } } if ($status==2) { if (substr($s,0,1)==" " || substr($s,0,1)==chr(9)) { $messageid.=" ".trim($s); $messageid=trim($messageid); } else { $status=0; } } if (substr($s,0,9)=="Received:") { $received=$s; $status=1; } if (preg_match("#^Message-ID:#i",$s)) { $messageid=trim(substr($s,11)); $status=2; } } // read the mail headers fclose($f); if ($status==1) { $received_list[]=$received; } if (!in_array($messageid,$message_list)) { $message_list[]=$messageid; // find the proper header of OUR SERVER receiving this mail foreach($received_list as $rec) { // skip localhost! (this is amavis talking to us ;) ) if (strpos($rec,"from localhost ")!==false) { continue; } if (strpos($rec,"from ".$hostname." ")!==false) { continue; } if (strpos($rec,"by ".$hostname." ")!==false) { // extract the sender of this email: if (preg_match("#\(Authenticated sender: ([^)]*)\)#",$rec,$from)) { } else { if (preg_match("#from ([^ ]*) #",$rec,$from)) { if ($from[1]=="userid") { continue; // skip locally generated mails } } else { $from=array("","<unknown>"); } } // this is the received header we want to find, parse it : if (preg_match("#\(using ([^ ]*) with cipher ([^ ]*) #",$rec,$mat)) { echo time()." ".$from[1]." ".$mat[1]." ".$mat[2]."\n"; } else { echo time()." ".$from[1]." NO NO\n"; // NO crypto was used ;((( } } } } // and delete this mail :) unlink($file); }
N’oubliez pas de modifier la ligne suivante qui se trouve au début du script :
$ROOT="PATH_DU_MAILDIR";
- On teste le fichier en le lançant :
php ssl.php
Si le test ne renvoie pas d’erreurs, on le planifie dans le cron pour le lancer toutes les minutes avec l’aide du fichier /etc/cron.d/ssl :
* * * * * root php /root/ssl.php 2>&1 >>/var/log/ssl.log
Après quelques minutes/heures de fonctionnement, on commencera à avoir dans le fichier /var/log/ssl.log les premiers détails comme ceux là :
1414506421 solo.fdn.fr TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 1414506541 pi.octopuce.fr TLSv1 DHE-RSA-AES256-SHA 1414506601 pi.octopuce.fr TLSv1 DHE-RSA-AES256-SHA 1414506601 brassens.heberge.info TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 1414506661 sf01smtp2.securityfocus.com NO NO 1414506781 out.smtpout.orange.fr NO NO
Ce qui permet de faire des stats rapides comme celle ci (combien de mails a-t-on reçu utilisant chaque protocole cryptographique) :
cat ssl.log|awk '{print $3}'|sort|uniq -c 932 NO 4 SSLv3 594 TLSv1 10 TLSv1.1 429 TLSv1.2