Rendre des logs anonymes

En tant qu'administrateur système, je gère un certains nombre de serveurs qui voient passer des données personnelles, soit en tant que simple intermédiaire (passerelle de messagerie) soit en tant que destination finale (connexion/authentification des utilisateurs). Ces serveurs stockent alors sous forme de fichier de log des quantités phénoménales de données nominatives comme des identifiants, des adresses email, des adresses IP. Ces données sont bien évidemment confidentielles, et seule une réquisition judiciaire peut m'autoriser à en divulguer tout ou partie. Je suis moi-même autorisé à les exploiter dans le cadre de mon travail, mais uniquement à des fins statistiques, ou pour vérifier le bon fonctionnement des systèmes.
Il peut pourtant arriver qu'on soit tenté de fournir des extraits de log à certaines personnes. Un jour ce sera pour un prestataire ou un support technique, un autre jour ce sera pour alimenter des chercheurs universitaires qui ont besoin de données brutes. Il est alors impératif de faire disparaître toute trace de données personnelles et nominatives de ces fichiers, tout en s'assurant que le destinataire des fichiers sera en mesure de faire son travail.
Les données doivent être anonymes, mais pour autant elles doivent rester intègres et cohérentes. Par exemple, il faut que l'on puisse suivre le trajet d'un message électronique entre le serveur d'entrée, l'antispam, la passerelle interne, et le serveur de stockage final, sans pour autant connaître ni l'adresse IP du serveur de provenance, ni les adresses email de l'expéditeur et des destinataires.
Après quelques recherches infructueuses, j'ai décidé de créer moi-même le script dont j'ai besoin pour rendre des log de serveurs de mails anonymes.
En Perl, le module IP::Anonymous fourni une méthode cryptographique puissante basée sur Crypto-PAN. Cette méthode permet de rendre les adresse IPv4 anonymes tout en préservant une très grande cohérence des données. Voyez cet exemple avec à gauche les IP réelles, et à droite les IP anonymes obtenues par chiffrement :

192.168.0.15 -> 54.42.0.48
192.168.0.20 -> 54.42.0.43
192.168.1.15 -> 54.42.1.56
192.168.1.20 -> 54.42.1.43

En me basant sur un exemple de script Perl utilisant IP::Anonymous, j'ai créé un script qui permet en plus de rendre anonyme les adresses email, les message-IDs, et les noms de machines. Ainsi, et à condition de rester en IPv4, le script final permet de rendre totalement anonyme des logs Postfix :

   1: #!/usr/bin/perl -wT
   2: 
   3: # script brodé à partir d'un exemple
   4: # trouvé en ligne sur le forum CPAN
   5: # http://cpanforum.com/posts/1304
   6: 
   7: # à utiliser sous la forme :
   8: # logs_anonymes.pl fichier.log > sortie_anonyme.log
   9: 
  10: use strict;
  11: $|=1;
  12: 
  13: use IP::Anonymous;
  14: use Digest::MD5;
  15: 
  16: # 32 integers entre 0 et 255 (jot -r 32 0 255)
  17: my @key = (135,229,13,26,29,84,46,37,231,95,211,
  18:            196,243,11,87,5,23,217,173,214,66,241,
  19:            164,67,132,149,161,151,114,137,238,75);
  20: 
  21: my $obj = new IP::Anonymous(@key);
  22: my $md5 = Digest::MD5->new;
  23: 
  24: # seed pour le md5 
  25: my $seed = '766326241f69b1244792587f556d02b8';
  26: 
  27: while(defined(my $line=<>)) {
  28:     chomp $line;
  29:     # les IP
  30:     if($line =~ /\d{1,3}(?:\.\d{1,3}){3}/) {
  31:         $line =~
  32:             s/(\d{1,3}(?:\.\d{1,3}){3})/$obj->anonymize($1)/eg;
  33:     }
  34:     # les adresses email et messageID
  35:     if($line =~ /[=< ][^@ ]*@/) {
  36:         $line =~
  37:             s/([=< ])([^@=< ]*@)/$1.$md5->add($seed)->add($2)->hexdigest."@"/eg;
  38:     }
  39:     # les hostnames
  40:     if($line =~ /([=< @])(([a-zA-Z0-9]***TRONQUÉ***|ZW)/i ) {
  41:         $line =~
  42:             s/([=< @])((?:(?:[a-zA-Z0-9]***TRONQUÉ***|ZW)/$1.$md5->add($seed)->add($2)->hexdigest.".".$3.".".$4/egi;
  43:     }
  44:     # suppression des HELO
  45:     if($line =~ /(helo=<[^>]*>)/i ) {
  46:         $line =~
  47:             s/(helo=<[^>]*>)//gi;
  48:     }
  49:     
  50:     print $line."\n";
  51: }

Attention : certaines lignes du script ci-dessus sont tronquées volontairement. Cliquez ici pour obtenir le code du script fonctionnel : logs_anonymes.pl.

Pour utiliser ce script, il vous faudra installer IP::Anonymous, comme ceci par exemple :

$ sudo cpan
cpan[1]> install IP::Anonymous

Il vous faudra aussi personnaliser le contenu de @key (lignes 17 à 19), en utilisant par exemple la commande jot pour générer une liste de 32 entiers aléatoires compris entre 0 et 255 :

$ jot -r -s , 32 0 255

@key doit être gardée secrète, donc votre script devra être lisible seulement par vous.
Pour finir il faudra personnaliser le contenu de $seed (ligne 25), en saisissant la chaîne de caractères qui vous plait.
Aux lignes 40 et 42 figure une liste quasi complète des TLD, obtenue auprès de l'IANA.

Pour utiliser le script, que vous aurez rendu exécutable, il suffit de l'invoquer comme cela :

$ /chemin/de/logs_anonymes.pl fichier.log > sortie_anonyme.log

Testé sous Mac OS X 10.6 et FreeBSD 8.

Enjoy.

2 comments

  1. Salut Patrick
    Juste pour dire merci pour ce script, je viens de le modder pour qu'il renvoie vers un syslog plutot que stdout.
    Au cas ou si tu as besoin du mod tu me dis.
    @+

  2. Merci pour ce retour !
    Je passe mon tour pour le mod, mais c'est cool de voir que mon vieux bout de script peut servir. Attention cependant, il y a eu pas mal de nouveaux TLD depuis 2011, il y a sans doute matière à mettre à jour la liste (ou mieux à trouver une regex fiable qui puissent correspondre aux actuels et aux futurs...)

Laisser un commentaire

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

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.