Validation @ Email

L’analyse d’une adresse Email

L’une des premières tâches à effectuer avant d’enquêter sur les propriétés d’une adresse de courriel est de vérifier sa validité. C’est suite à une recherche approfondie que j’ai pu mettre au point un protocole doté de plusieurs étapes de validation permettant de certifier l’existence du compte de messagerie destinataire. Notons qu’il ne nous sera pas possible de garantir l’inexistence d’un compte par une simple analyse des protocoles DNS et SMTP : il subsiste un taux minimal de faux négatifs.

Les normes RFC

La première des vérifications est celle du formatage de l’adresse par le respect des expressions régulières définies dans les spécifications RFC. Nous nous contenterons d’un mélange basique fourni par les RFC 822, 1035 et 2822.

Voici notre premier critère de validation sous la forme d’une grammaire G :

// Grammaire G
G = Ante . ‘@’ . Post

// Ante représente la partie à gauche de l’arobase
Ante = Atom1+ (‘.’ Atom1+)*
// Post représente la partie à droite de l’arobase
Post = (1 à 63 caractères parmi Atom2 séparés par des points) . (2 à 63 caractères parmi Atom2)

// Atom1 représente les tokens de la partie gauche
Atom1 = [-a-z0-9!#$%&\'*+\\/=?^_`{|}~]
// Atom2 représente les tokens de la partie droite
Atom2 = [a-z0-9] ([-a-z0-9]* [a-z0-9]+ )?

Pour que l’adresse soit reconnue comme étant correctement formée, elle doit respecter la grammaire ci-dessus. Cette étape sera réalisée par un script PHP, à l’aide de la fonction « preg_match ».

Exemple : formatage des adresses de courriel.

j-m.larquet@club-internet.fr : Adresse de courriel valide
<Jibril.cissé>@gmail.com : Adresse de courriel non valide

Cette pré-étude nous permet d’écarter la majorité des adresses malformées et par là-même inexistantes. Cette étape validée, nous allons nous intéresser aux informations disponibles à partir des serveurs de noms.

Le protocole DNS

Celui-ci permet la résolution des noms en adresse IP, mais il propose aussi de nombreux autres services spécialisés. Nous nous attarderons sur deux informations capitales pour notre problématique : le Full Qualified Domain Name (F.Q.D.N.) ainsi que la liste des Mail eXchangers (M.X.).

Le F.Q.D.N. nous fournit la liste des adresses IP relatives aux serveurs connus pour le nom de domaine de départ. Cela nous permettra de vérifier au préalable si le nom de domaine est connu de notre serveur DNS. Il sera donc souhaitable de recourir à un serveur mondialement réputé tel que ceux proposés par la société américaine Open DNS.

Exemple : requête F.Q.D.N. via Nslookup.

C:\Documents and Settings\Arnaud Aucher>nslookup
Serveur par défaut : quickspot.wave-storm.com
Adresse: 192.168.0.1

> aucher.net
Serveur : quickspot.wave-storm.com
Adresse: 192.168.0.1

Réponse ne faisant pas autorité :
Nom : aucher.net
Adresses: 213.251.145.240, 213.251.145.231, 213.251.152.101, 213.251.145.237

Une fois le test du F.Q.D.N. passé, nous interrogerons le serveur DNS afin d’obtenir la liste des M.X. relatifs au nom de domaine. Cette liste, si elle existe, implique l’existence de serveurs de messagerie. Cela nous permettra d’interroger le serveur sur l’existence du compte de messagerie pour le client donné via le protocole SMTP.

Exemple : requête M.X. via Nslookup.

> set q=mx
> aucher.net
Serveur : quickspot.wave-storm.com
Adresse: 192.168.0.1

Réponse ne faisant pas autorité :
aucher.net MX preference = 10, mail eXchanger = mx10.aucher.net
aucher.net MX preference = 20, mail eXchanger = mx20.aucher.net

Le cahier des charges spécifiant que le nombre de services offerts par l’hébergeur est limité, nous ne disposerons pas de la bibliothèque PEAR. Nous avons donc codé un script de dialogue avec un serveur DNS.

Notons que le protocole DNS repose sur le protocole UDP fonctionnant en mode non connecté. Notre analyse ne s’effectuant pas progressivement, il nous faut attendre la réception totale de tout le message avant de l’analyser. C’est la raison pour laquelle l’analyse d’une adresse de courriel demande un certain temps d’exécution (environ 10 secondes par requête UDP).

Les requêtes DNS

Afin de comprendre le formatage des requêtes DNS, je me suis procuré l’ouvrage « DNS et BIND » aux éditions O’REILLY. Cet ouvrage m’a permis de mieux aborder le fonctionnement du protocole DNS ainsi que les RFC 883 et 1035. En effet, j’y ai appris l’existence de Nslookup : outil indispensable pour comprendre les principes de base d’un serveur de noms. L’utilisation de Arnaud Aucher Page 12/30 2006 – 2007 Wireshark (anciennement Ethereal) m’a aussi permis d’observer et de corriger le formatage de mes requêtes.

Voici un petit aperçu des requêtes échangées lors du processus d’analyse de l’adresse de messagerie. Nous allons interroger le serveur DNS afin d’obtenir les noms des serveurs de messagerie répertoriés pour le domaine « aucher.net ». Chaque requête est analysée codée (ou décodée) avec de nombreuses conversions entre code ASCII, Binaire, et Hexadécimale.

Exemple : requête M.X. (Application Serveur DNS).

Transaction ID : 0×0005
Flags : 0×0100 (Standard query)
0… …. …. …. = Response : Message is a query
.000 0… …. …. = Opcode : Standard query (0)
…. ..0. …. …. = Truncated : Message is not truncated
…. …1 …. …. = Rescursion desired : Do query recursively
…. …. .0.. …. = Z : Reserved (0)
…. …. …0 …. = Non-authenticated data OK : Unacceptable
Questions : 0×0001
Answer RRs : 0×0000
Authority RRs : 0×0000
Additional RRs : 0×0000
Query :

aucher.net : Type MX, Class IN
Name : aucher.net : 0×0661 7563 6865 7203 6E65 7400
Type : MX (Mail eXchanger) : 0×000F
Class : IN : 0×0001

Exemple : réponse M.X. (Serveur DNS Application).

Transaction ID : 0×0005
Flags : 0×8180 (Standard query response, No error)
1… …. …. …. = Response : Message is a response
.000 0… …. …. = Opcode : Standard query (0)
…. .0.. …. …. = Authoritative : Not an authority for the domain
…. ..0. …. …. = Truncated : Message is not truncated
…. …1 …. …. = Rescursion desired : Do query recursively
…. …. 1… …. = Recurtion available : Server can do recursive queries
…. …. .0.. …. = Z : Reserved (0)
…. …. ..0. …. = Answer authenticated : authority not authenticated
…. …. …. 0000 = Reply code : No error
Questions : 0×0001
Answer RRs : 0×0002
Authority RRs : 0×0000
Additional RRs : 0×0000
Query :

aucher.net : Type MX, Class IN
Name : aucher.net : 0×0661 7563 6865 7203 6E65 7400
Type : MX (Mail eXchanger) : 0×000F
Class : IN : 0×0001

Answers :
aucher.net : Type MX, Class IN, preference 10, mx mx10.aucher.net

Name : aucher.net : 0xC00C
Type : MX (Mail eXchanger) : 0×000F
Class : IN : 0×0001
Time To Live : 23h 58m 42s : 0×0001 5132
Data Length : 9 : 0×0009
Preference : 10 : 0×000A
Mail eXchanger : mx10.aucher.net : 0×046D 7831 30C0 0C

aucher.net : Type MX, Class IN, preference 20, mx mx20.aucher.net

Name : aucher.net : 0xC00C
Type : MX (Mail eXchanger) : 0×000F
Class : IN : 0×0001
Time To Live : 23h 58m 42s : 0×0001 5132
Data Length : 9 : 0×0009
Preference : 10 : 0×0014
Mail eXchanger : mx10.aucher.net : 0×046D 7832 30C0 0C

Les informations récupérées après l’analyse sont les suivantes :

  • aucher.net : Type MX, Class IN, preference 10, mx mx10.aucher.net
  • aucher.net : Type MX, Class IN, preference 20, mx mx20.aucher.net

On y retrouve les noms des serveurs de messagerie correspondant au nom de domaine « aucher.net », ceux-ci étant classés par ordre croissant de préférence.

L’une des difficultés rencontrées fut de gérer à l’intérieur de la requête, les pointeurs de chaînes déjà saisies dans le message courant. En effet, il existe des règles pour la compression des requêtes suivant le protocole DNS : un nom de domaine peut être représenté de 3 façons :

  • Une séquence de labels finissant par un octet à 0 ;
  • Un pointeur ;
  • Une séquence de labels finissant par un pointeur.

Voici la structure des différents types :

Exemple : Type label.

+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+
|.0.0.|……….Taille de la chaine à suivre ……….|
+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

Les 2 premiers bits sont à 0.

Exemple : Type pointeur.

+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+
|.1.1.|…………………………Offset…………………………|
+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

Les 2 premiers bits sont à 1.

Une lecture approfondie des spécifications et une analyse bas niveau des requêtes m’ont permis de surmonter cette difficulté. J’ai donc dû distinguer les différents types de représentation afin d’intégrer leur gestion au sein de mes algorithmes. Mes fonctions supportent maintenant parfaitement les différentes représentations.

Le protocole SMTP

Une fois la liste des M.X. obtenue, ils sont triés par ordre de préférence. Nous choisissons donc le serveur de messagerie préféré, pour initialiser une connexion SMTP sur un socket TCP.

Notons que le mode connecté de TCP nous permet ici de traiter les réponses en instantané car le message émis est sûr d’arriver à son destinataire en intégralité. Il n’y a pas de perte de paquets comme en UDP.

Une fois la connexion initiée, nous allons tenter d’amorcer la séquence d’envoi d’un message électronique au compte client hébergé sur le serveur. Voici la séquence en question :

// Connexion au serveur SMTP
> 220 AdresseDuM.X.

// Initialisation
HELO gmail.com\r\n
> 250 NotreNomDHôte

// Emetteur
MAIL FROM: <{postmaster@gmail.com}>\r\n
> 250 OK

// Destinataire
RCPT TO: <{EmailCible}>\r\n
> 250 OK
// Ou
> 550 5.1.1 user unknown

// Sortie
QUIT\r\n
> 250 OK

Pour des mesures de sécurité, les serveurs de messagerie actuels ne renvoient pas toujours le bon code d’erreur (550 5.1.1 user unknown). Nous imaginerons facilement un spammeur muni d’un script initialisant des connexions sur des noms de comptes de messagerie sortis d’un annuaire ou d’un dictionnaire.

Une autre contremesure est fonction du nombre de connexions échouées, en effet certains serveurs possèdent des listes noires identifiant les émetteurs récidivistes comme spammeurs.

En revanche dans la majorité des cas, ils répondent correctement à l’envoi d’un message ayant un compte client répertorié sur leur serveur. C’est la raison pour laquelle, si le message 250 OK apparaît, on classe l’adresse cible comme valide. Dans le cas contraire, elle sera reconnue comme non valide.