web-dev-qa-db-fra.com

Validation sécurisée des e-mails

J'utilise cette expression régulière compatible RFC822 pour la validation des e-mails. Les testeurs de stylo sur HackerOne ont utilisé les adresses e-mail horribles suivantes qui satisfont l'expression régulière:

Ces adresses e-mail sont-elles valides? Comment puis-je faire une validation sécurisée des e-mails?

32
Randomblue

Ces adresses e-mail sont-elles valides?

Oui, ils sont. Voir par exemple ici ou avec un peu plus d'explication ici .

Pour une belle explication sur l'apparence des e-mails, consultez les informations RFC3696 . Les RFC les plus techniques y sont également liés.

Attaques possibles dans la partie locale d'une adresse e-mail

Sans guillemets, les pièces locales peuvent consister en toute combinaison de
caractères alphabétiques, chiffres ou l'un des caractères spéciaux

  ! # $ % & ' * + - / = ?  ^ _ ` . { | } ~

la période (".") peut également apparaître, mais ne peut pas être utilisée pour démarrer ou terminer la partie locale, ni deux périodes consécutives ou plus. Autrement dit, tout caractère graphique ASCII (impression) autre que le signe at ("@"), la barre oblique inverse, les guillemets doubles, les virgules ou les crochets peuvent apparaître sans guillemets. la liste des caractères exclus doit apparaître, ils doivent être cités.

La règle est donc plus ou moins: la plupart des caractères peuvent faire partie de la partie locale, à l'exception de @\",[], Ceux-ci doivent être entre " (Sauf bien sûr " Lui-même , qui doit être échappé dans une chaîne entre guillemets).

Il y a également des règles sur où et quand citer et comment gérer les commentaires, mais cela est moins pertinent pour votre question.

Le point ici est que de nombreuses attaques peuvent faire partie de la partie locale d'une adresse e-mail, par exemple:

  • '/**/OR/**/1=1/**/--/**/@a.a
  • "<script>alert(1)</script>"@example.com
  • " onmouseover=alert(1) foo="@example.com
  • "../../../../../test%00"@example.com
  • ...

Attaques possibles dans la partie domaine d'une adresse e-mail

La structure exacte de la partie domaine peut être vue dans RFC2822 ou RFC5322 :

addr-spec       =       local-part "@" domain

local-part      =       dot-atom / quoted-string / obs-local-part

domain          =       dot-atom / domain-literal / obs-domain

domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]

dcontent        =       dtext / quoted-pair

dtext           =       NO-WS-CTL /     ; Non white space controls

                        %d33-90 /       ; The rest of the US-ASCII
                        %d94-126        ;  characters not including "[",
                                        ;  "]", or "\"

Où:

   dtext           =   %d33-90 /          ; Printable US-ASCII
                       %d94-126 /         ;  characters not including
                       obs-dtext          ;  "[", "]", or "\"

Vous pouvez voir que la plupart des caractères sont autorisés (même caractères non ascii ). Les attaques possibles seraient:

  • [email protected]&a=////etc/passwd
  • foo@bar(<script>alert(1)</script>).com
  • foo@'/**/OR/**/1=1/**/--/**/

Conclusion

Vous ne pouvez pas valider les adresses e-mail en toute sécurité.

Au lieu de cela, vous devez vous assurer d'avoir les défenses appropriées en place (encodage HTML pour XSS, instructions préparées pour l'injection SQL, etc.).

Comme défense en profondeur, vous pouvez interdire aux chaînes et aux commentaires cités de gagner une certaine protection, car ces deux choses autorisent les caractères et les chaînes les plus inhabituels. Mais certaines attaques sont toujours possibles et vous exclurez un petit nombre d'utilisateurs.

Si vous avez besoin d'un filtrage d'entrée supplémentaire qui dépasse les limites du format de courrier électronique, car vous ne faites pas confiance au reste de votre application, vous devez soigneusement considérer ce que vous autorisez et ce que vous n'autorisez pas. Par exemple, + Est utilisé par gmail pour autoriser le filtrage des e-mails entrants, donc ne pas l'autoriser peut conduire les utilisateurs à ne pas s'inscrire. D'autres caractères peuvent être utilisés par d'autres fournisseurs pour des fonctionnalités similaires. Une première approche pourrait consister à n'autoriser que alphanum + ! # % * + - = ? ^ _ . | ~. Cela interdirait < > ' " ` / $ { } &, Qui sont des caractères utilisés dans les attaques courantes. Selon votre application, vous souhaiterez peut-être interdire d'autres caractères.

Et comme vous l'avez mentionné RFC822 : C'est un peu dépassé (c'est de 1982), mais même cela permet de citer des chaînes et des commentaires, donc dire simplement que vous n'acceptez que des adresses conformes à RFC822 ne serait pas seulement non pratique , mais aussi ne fonctionne pas.

Vérifiez-vous également vos e-mails côté client? Le code JS donne cette impression. Un attaquant pourrait simplement contourner les vérifications côté client.

40
tim

Le moyen le plus simple de tester cela serait d'essayer d'envoyer un e-mail à cette adresse, à partir d'une adresse d'envoi uniquement (c'est-à-dire de [email protected]). S'il ne peut pas être livré, il n'est pas valide.

L'utilisation d'une expression rationnelle pour analyser les e-mails est probablement préférable du côté client pour leur faire savoir à l'avance qu'ils peuvent avoir des fautes de frappe dans leur adresse e-mail, avant ils s'inscrivent.

10
Philip Rowlands

Vous dites que vous souhaitez avoir des adresses e-mail sécurisées . Je suppose que cela signifie que ceux-ci sont mis dans votre application et que vous attendez une sortie prévisible. Les développeurs qui écrivent votre application ont dans leur tête collective une idée de ce à quoi s'attendre à l'intérieur d'un champ e-mail, et vous feriez mieux de ne rien y autoriser. Ce que vos programmeurs n'attendent pas n'est pas très sûr (même s'il est valide selon certains RFC horribles).

Donc, si vos développeurs ne s'intéressent pas beaucoup aux RFC liés aux e-mails, je suggère d'utiliser "une violation délibérée de la RFC 5322" qui se trouve dans un Norme W3C pour HTML5, et se traduit par une expression régulière assez simple:

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

source http://www.w3.org/TR/html5/forms.html#valid-e-mail-address

Au cas où cela serait trop laxiste (si vous pensez que vos développeurs ne s'attendent pas à ces étranges #$%&| etc), je suggère de le sécuriser un peu plus:

^[a-zA-Z0-9.+/=?^_-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$

Je pense que 99,9% des adresses réelles correspondent à ces deux expressions.

8
kubanczyk

Vous pouvez passer trop de temps à vous soucier de ce genre de chose. Pourquoi vous souciez-vous vraiment autant?

Il n'y a pas vraiment d'adresse non sécurisée en tant que telle - c'est ce que vous en faites/comment vous la traitez qui compte.

Si vous traitez l'adresse de manière non sûre, par exemple concaténer une chaîne pour faire sql au lieu d'utiliser des paramètres, vous demandez des problèmes, pas seulement dans les adresses e-mail, mais dans tous les champs que vous autorisez l'utilisateur à saisir.

Tout simplement; à condition qu'il

[>= one char]@[>= one char].[>= one char]

ou même simplement:

[>= one char]@[>= one char]

vous devez l'autoriser. Peu importe ce que sont ces caractères.

4
Matt Wilko

Les réponses qui soulignent la nécessité d'utiliser une approche en couches plutôt que de s'appuyer sur un seul filtre ou une seule défense sont sur la bonne voie. Il existe des tas d'articles sur l'écriture de l'expression rationnelle "correcte" pour valider une adresse e-mail. La réalité est que vous devez combiner un certain nombre de vérifications et ne pouvez pas simplement compter sur une expression rationnelle.

Les contrôles dont vous aurez besoin dépendront de ce que vous essayez de faire et des risques auxquels vous essayez de vous protéger. Si vous essayez simplement d'identifier les spammeurs, vous devrez peut-être également consulter le contenu, les lignes d'objet et les serveurs de messagerie d'origine. D'un autre côté, si vous essayez de vérifier une adresse e-mail pour un processus d'enregistrement, vous pouvez vouloir vérifier le domaine, éventuellement ajouter un processus de confirmation qui envoie un message à l'adresse, etc.

Mon conseil est similaire à @MattWilko - vous obtenez rapidement des rendements décroissants lorsque vous essayez de dériver l'expression rationnelle parfaite. Au fur et à mesure que votre expression devient plus complexe, vous attraperez plus de mauvaises adresses, mais vous augmenterez certainement le nombre de faux positifs. La clé est de trouver le bon équilibre et cet équilibre dépendra de votre cas d'utilisation et des risques contre lesquels vous tenterez de vous protéger.

0
Tim X