Validación segura del correo electrónico

30

He estado utilizando esta expresión regular compatible con RFC822 para la validación de correo electrónico. Los evaluadores de lápiz en HackerOne han usado las siguientes direcciones de correo electrónico horrendas que satisfacen la expresión regular:

¿Son válidas esas direcciones de correo electrónico? ¿Cómo puedo hacer la validación segura de correo electrónico?

    
pregunta Randomblue 01.03.2016 - 09:40
fuente

5 respuestas

39
  

¿Son válidas esas direcciones de correo electrónico?

Sí, lo son. Consulte por ejemplo aquí o con un poco más de explicación aquí .

Para obtener una explicación detallada sobre el aspecto de los correos electrónicos, consulte la información RFC3696 . Los RFC más técnicos también están vinculados allí.

Ataques posibles en la parte local de una dirección de correo electrónico

  

Sin comillas, las partes locales pueden consistir en cualquier combinación de
  Caracteres alfabéticos, dígitos o cualquiera de los caracteres especiales

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

período (".") también puede aparecer, pero no puede usarse para comenzar o terminar   La parte local, ni pueden aparecer dos o más periodos consecutivos.   Dicho de otra manera, cualquier carácter ASCII gráfico (impresión) otro   que el signo de at ("@"), barra invertida, comillas dobles, comas o cuadrados   Los corchetes pueden aparecer sin citar. Si alguno de esa lista de   Los caracteres excluidos deben aparecer, deben estar entre comillas.

Entonces, la regla es más o menos: la mayoría de los caracteres pueden ser parte de la parte local, excepto por @\",[] , estos deben estar entre " (excepto por supuesto " en sí mismo, que debe ser evitado) cuando en una cadena entre comillas).

También hay reglas sobre dónde y cuándo citar y cómo manejar los comentarios, pero eso es menos relevante para su pregunta.

El punto aquí es que muchos ataques pueden ser parte de la parte local de una dirección de correo electrónico, por ejemplo:

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

Ataques posibles en la parte del dominio de una dirección de correo electrónico

La estructura exacta de la parte del dominio se puede ver en RFC2822 o 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 "\"

Donde:

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

Puede ver que, una vez más, la mayoría de los caracteres están permitidos (incluso caracteres no ascii ). Los posibles ataques serían:

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

Conclusión

No puedes validar las direcciones de correo electrónico de forma segura.

En su lugar, debe asegurarse de tener las defensas adecuadas en su lugar (codificación HTML para XSS, declaraciones preparadas para inyección SQL, etc.).

Como defensa en profundidad, podría prohibir cadenas y comentarios entre comillas para obtener cierta protección, ya que estas dos cosas permiten los caracteres y cadenas más inusuales. Pero algunos ataques siguen siendo posibles, y excluirás a una pequeña cantidad de usuarios.

Si necesita un filtro de entrada adicional que exceda los límites del formato de correo electrónico, ya que no confía en el resto de su aplicación, debe considerar cuidadosamente lo que permite y lo que no permite. Por ejemplo, gmail utiliza + para permitir el filtrado de correos electrónicos entrantes, por lo que no permitir que los usuarios no puedan registrarse. Otros proveedores pueden utilizar otros caracteres para funcionalidades similares. Un primer enfoque podría ser permitir solo alfanum + ! # % * + - = ? ^ _ . | ~ . Esto no permitiría < > ' " ' / $ { } & , que son caracteres utilizados en ataques comunes. Dependiendo de su aplicación, es posible que desee no permitir más caracteres.

Y como mencionó RFC822 : está un poco desactualizado (es de 1982), pero incluso permite cadenas y comentarios entre comillas, por lo que solo decir que solo acepta las direcciones compatibles con RFC822 no solo no sería práctico, sino que tampoco funcionaría.

Además, ¿está revisando sus correos electrónicos del lado del cliente? El código JS da esa impresión. Un atacante podría simplemente pasar por alto las verificaciones del lado del cliente.

    
respondido por el tim 01.03.2016 - 10:31
fuente
10

La forma más sencilla de probar esto sería intentar enviar un correo electrónico a esa dirección, desde una dirección de solo envío (es decir, desde [email protected]). Si no se puede entregar, no es válido.

El uso de una expresión regular para analizar correos electrónicos probablemente se haga mejor en el lado del cliente para informarles de antemano que pueden tener errores tipográficos en su dirección de correo electrónico, antes de que se registren.

    
respondido por el Philip Rowlands 01.03.2016 - 10:21
fuente
8

Dice que desea tener direcciones de correo electrónico seguras . Supongo que esto significa que se colocan en tu aplicación y esperas un resultado predecible. Los desarrolladores que escriben su aplicación tienen en su cabeza colectiva alguna idea de qué esperar dentro de un campo de correo electrónico, y es mejor que no permita nada más allí. Lo que sus programadores no esperan no es muy seguro (incluso si es válido de acuerdo con algunas RFC horribles).

Entonces, si sus desarrolladores no están muy interesados en los RFC relacionados con el correo electrónico, sugiero usar "una violación intencional de RFC 5322" que existe dentro de un estándar W3C para HTML5, y se traduce a una expresión regular bastante 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])?)*$

fuente enlace

En caso de que sea demasiado relajado (si crees que tus desarrolladores no esperan esos #$%&| , etc. extraños), sugiero asegurarlo un poco más:

^[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])?)+$

Creo que el 99.9% de las direcciones de personas reales coinciden con estas dos expresiones.

    
respondido por el kubanczyk 01.03.2016 - 21:54
fuente
4

Puedes pasar demasiado tiempo preocupándote por este tipo de cosas. ¿Por qué te importa tanto?

Realmente no hay una dirección insegura como tal, lo que cuenta es lo que haces con ella / cómo lo procesas.

Si procesa la dirección de forma no segura, por ejemplo. concatenando una cadena para hacer sql en lugar de usar parámetros, entonces está pidiendo problemas, no solo en las direcciones de correo electrónico, sino en todos los campos que le permite al usuario ingresar.

Simplemente poner; siempre que tenga

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

o incluso simplemente:

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

debes permitirlo. Realmente no importa cuáles son esos caracteres.

    
respondido por el Matt Wilko 02.03.2016 - 11:26
fuente
0

Las respuestas que enfatizan la necesidad de utilizar un enfoque en capas en lugar de confiar en un solo filtro o defensa están en el camino correcto. Hay montones de artículos por ahí sobre cómo escribir la expresión regular "correcta" para validar una dirección de correo. La realidad es que necesita combinar varios controles y no puede simplemente confiar en una expresión regular.

Los controles que necesite dependerán de lo que trata de hacer y de los riesgos contra los que trata de protegerse. Si solo está tratando de identificar a los remitentes de correo no deseado, es posible que también deba mirar el contenido, las líneas de asunto y los servidores de correo originales. Por otro lado, si está intentando verificar una dirección de correo para un proceso de registro, es posible que desee verificar el dominio, posiblemente agregar un proceso de confirmación que envíe un mensaje a la dirección, etc.

Mi consejo es similar a @MattWilko: pronto obtendrás rendimientos decrecientes cuando trates de obtener la expresión regular perfecta. A medida que su expresión se vuelva más compleja, capturará más direcciones erróneas, pero casi con seguridad también aumentará el número de falsos positivos. La clave es encontrar el equilibrio adecuado y ese equilibrio dependerá de su caso de uso y de los riesgos que intenta proteger.

    
respondido por el Tim X 04.03.2016 - 02:49
fuente

Lea otras preguntas en las etiquetas