¿Debo desinfectar una dirección de correo electrónico antes de pasarla a la función is_email ()?

13

Estoy usando is_email()para verificar si una dirección de correo electrónico proporcionada por el usuario es válida. Por ejemplo:

$email = $_POST['email'];
if ( is_email( $email ) )
    // Do something.

Que yo sepa, nada en esta función escribe información en la base de datos. ¿Debería desinfectar $emailantes de pasarlo a la función?

henrywright
fuente
Kaiser, gracias por la edición. En realidad, es desinfección para mí, pero estoy seguro de que la mayoría de los lectores usarán una z :)
henrywright

Respuestas:

5

Mirando la is_email()funcionalidad en trac, parece que no necesita sanatizar, ya que solo se trata de pruebas de cadena. Incluso iría tan lejos como para decir que si esta función devuelve verdadero, no necesitaría desinfectarla antes de enviarla a la base de datos.

Howdy_McGee
fuente
Mis pensamientos exactamente sobre la prueba de cuerdas. Creo que todavía desinfectaré antes de enviarlo a la base de datos, probablemente tengas razón en que no es necesario, pero estoy muy nervioso cuando se trata de estas cosas :)
henrywright
Es cierto, más vale prevenir que curar y la sobrecarga de desinfección sería completamente imperceptible.
Howdy_McGee
18

WordPress y núcleo de PHP

La is_email()función Fuente es una implementación típica de WordPress y no funciona completamente con lo que permite el RFC 6531 . Una razón podría ser que la FILTER_VALIDATE_EMAILconstante de PHP predeterminada filter_var()no es mucho mejor para validar algo de acuerdo con las pautas del Grupo de trabajo de ingeniería de Internet (IETF®) .

Normas

El punto es que el RFC 6531 permite "caracteres Unicode más allá del rango ASCII" . Es decir, esos son (para la parte local, antes de @):

  • Letras inglesas en mayúsculas y minúsculas (a – z, A – Z) (ASCII: 65–90, 97–122)
  • Dígitos 0a 9(ASCII: 48–57)
  • Estos personajes especiales: ! # $ % & ' * + - / = ? ^ _ ` { | } ~
  • Carácter .(punto, punto, punto final) (ASCII: 46) siempre que no sea el primer o el último carácter, y siempre que no aparezca consecutivamente (por ejemplo, [email protected]no está permitido).
  • Se permiten caracteres especiales con restricciones. Son:
    • Espacio y "(),:;<>@[\](ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91–93)
    • Las restricciones para los caracteres especiales son que solo deben usarse cuando están entre comillas, y que 2 de ellas (la barra invertida \ y la comilla "(ASCII: 92, 34)) también deben ir precedidas de una barra invertida \(por ejemplo, "\\"y "\"") .
  • Se permiten comentarios con paréntesis en cada extremo de la parte local; por ejemplo, john.smith(comment)@example.comy (comment)[email protected]son equivalentes a "[email protected]", pero john.(comment)[email protected]serían inválidos.
  • Los caracteres internacionales anteriores U+007F, codificados como UTF-8, están permitidos por RFC 6531, aunque los sistemas de correo pueden restringir qué caracteres usar al asignar partes locales.

y para la parte global / dominio:

La parte del nombre de dominio de una dirección de correo electrónico debe cumplir con pautas estrictas: debe coincidir con los requisitos para un nombre de host, que consta de letras, dígitos, guiones y puntos. Además, la parte del dominio puede ser un literal de dirección IP, rodeado de corchetes, como jsmith@[192.168.2.1]o jsmith@[IPv6:2001:db8::1][…]

Fuente: Wikipedia

¿Qué es válido?

Esto puede conducir a direcciones de correo electrónico extrañas pero válidas como las siguientes:

  • [email protected]
  • (comment)[email protected]
  • "this is v@lid!"@example.com
  • "much.more unusual"@example.com
  • postbox@com
  • admin@mailserver1
  • "()<>[]:,;\\@\"\\\\!#$%&\'*+-/=?^_`{}| ~.a"@example.org
  • " "@example.org

Fuente: php.net / author [email protected] - ejemplo arreglado por el autor de esta publicación

Límites

También hay límites de longitud locales y de dominio:

El formato de las direcciones de correo electrónico es local-part@domaindonde la parte local puede tener hasta 64 caracteres y el nombre de dominio puede tener un máximo de 253 caracteres , pero la longitud máxima de 256 caracteres de una ruta de reenvío o reversa restringe toda la dirección de correo electrónico a no debe tener más de 254 caracteres de longitud . [2] Las definiciones formales se encuentran en RFC 5322 (secciones 3.2.3 y 3.4.1) y RFC 5321, con una forma más legible en el RFC 3696 informativo [3] y las erratas asociadas .

Fuente: Wikipedia

Restricciones de WordPress

Y esto es lo que WordPress busca:

  • Pruebe la longitud mínima que puede tener el correo electrónico: strlen( $email ) < 3
  • Prueba un carácter @ después de la primera posición: strpos( $email, '@', 1 ) === false
  • Prueba de caracteres no válidos: !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local )
  • Prueba de secuencias de períodos: preg_match( '/\.{2,}/', $domain )
  • Prueba de períodos iniciales y finales y espacios en blanco: trim( $domain, " \t\n\r\0\x0B." ) !== $domain
  • Suponga que el dominio tendrá al menos dos subs: $subs = explode( '.', $domain );y luego
    • 2 > count( $subs )
    • trim( $sub, " \t\n\r\0\x0B-" ) !== $sub
    • !preg_match('/^[a-z0-9-]+$/i', $sub )

Fuente: WP Core v4.0

Filtros y validación personalizada

Todos los casos mencionados anteriormente se activarán is_email()para devolver falso. El resultado es filtrable (se puede adjuntar una devolución de llamada) y el filtro tendrá tres argumentos, donde el último argumento es el motivo. Ejemplo:

return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );

lo que significa que puede anular los resultados devueltos por verificaciones específicas.

Esto le permite agregar controles especiales, por ejemplo, para permitir dominios Umlaut, partes de dominio solo para TLD, etc.

Conclusión

WordPress es seguro para la mayoría de los casos, pero más restrictivo ya que los servidores de correo deben ser compatibles con RFC. Tenga en cuenta que no todos los servidores de correo se alinearán con las pautas de RF 6531.

Editar

Dato curioso: dentro hay dos funciones relacionadas ~/wp-includes/formatting: is_email()y sanitize_email(). Son prácticamente la misma función. No tengo idea de por qué alguien decidió que sería una buena idea copiar los contenidos de la función de uno a otro en lugar de simplemente agregar uno como devolución de llamada a los filtros que proporciona el otro. Como desde la v0.71 y desde la v1.5 son iguales, personalmente usaría la última cuando obtenga una cadena limpia. Tenga en cuenta que incluso afirma que no es compatible con RFC.is_email() sanitize_email() is_email()

emperador
fuente
Entonces, ¿estás diciendo que, en teoría, habrá direcciones de correo electrónico que son completamente válidas de acuerdo con RFC 6531 pero WordPress las considerará inválidas?
henrywright
Algunos sí. Por ejemplo, dominios solo de TLD, dominios de diéresis, etc., como puede leer en el último párrafo antes de la conclusión en la respuesta. Por favor lea la respuesta nuevamente. Sé que es mucho para entenderlo, pero vale la pena.
kaiser
1
De hecho, ¡ya lo leí dos veces, ya que es algo que vale la pena entender! Gracias por una respuesta tan detallada :)
henrywright
2

¡Desinfecta todas las cosas!

Una de las reglas cardinales de seguridad es no confiar nunca en la información del usuario. En general, no me importa la implementación de is_email () o cualquier otra función específica, o si esa función hace algo peligroso con lo que le doy. Quizás la implementación cambie algún día. Quién sabe. Tengo que asumir que puede verse comprometido. La suposición siempre debe ser que la entrada del usuario es activamente hostil, doblemente para cualquier cosa destinada eventualmente a una base de datos, y para desinfectar cada bit de entrada del usuario antes de pasarlo a alguna función. Esto es simplemente bueno, higiene de seguridad general.

JesseM
fuente
Creo que has dado en el clavo cuando dijiste que nunca sabes si la implementación cambiará. Puede estar bien no desinfectar ahora, pero ¿quién sabe si eso cambiará en una fecha posterior?
henrywright