Devo limpar um endereço de email antes de passá-lo para a função is_email ()?

13

Estou usando is_email()para verificar se um endereço de email fornecido pelo usuário é válido. Por exemplo:

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

Que eu saiba, nada nesta função grava informações no banco de dados. Devo higienizar $emailantes de passar para a função?

Henry Wright
fonte
Kaiser, obrigado pela edição. É realmente sanitização para mim, mas eu tenho certeza que a maioria de leitores aqui vai usar um z :)
henrywright

Respostas:

5

Olhando para a is_email()funcionalidade no trac, parece que você não precisa sanitizie, pois é apenas um teste de cadeia. Eu chegaria ao ponto de dizer que, se essa função retornar verdadeira, você não precisaria limpá-la antes de enviá-la para o banco de dados.

Howdy_McGee
fonte
Meus pensamentos exatamente sobre o teste de cordas. Acho que vou ainda sanitize antes de enviar para o db, provavelmente você está certo de que não é necessário, mas eu sou uma pilha de nervos quando se trata dessas coisas :)
henrywright
É verdade que é melhor prevenir do que remediar e a sobrecarga de higienização seria totalmente imperceptível.
Howdy_McGee
18

WordPress e núcleo PHP

A is_email()função Source é uma implementação típica do WordPress e não funciona completamente com o que o RFC 6531 permite. Uma razão pode ser que a FILTER_VALIDATE_EMAILconstante PHP padrão para filter_var()não seja muito melhor na validação de algo de acordo com as diretrizes da IETF (The Internet Engineering Task Force) .

Padrões

O ponto é que o RFC 6531 permite "caracteres Unicode além do intervalo ASCII" . Ou seja, esses são (para a parte local - antes da @):

  • Letras maiúsculas e minúsculas em inglês (a – z, A – Z) (ASCII: 65–90, 97–122)
  • Dígitos 0para 9(ASCII: 48–57)
  • Esses caracteres especiais: ! # $ % & ' * + - / = ? ^ _ ` { | } ~
  • Caractere .(ponto, ponto, ponto final) (ASCII: 46), desde que não seja o primeiro ou o último caractere, e também que não apareça consecutivamente (por exemplo, [email protected]não é permitido).
  • Caracteres especiais são permitidos com restrições. Eles são:
    • Espaço e "(),:;<>@[\](ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91-93)
    • As restrições para caracteres especiais são que eles só devem ser usados ​​quando estiverem entre aspas e que 2 deles (a barra invertida \ e as aspas "(ASCII: 92, 34)) também devem ser precedidos por uma barra invertida \(por exemplo, "\\"e "\"") .
  • Os comentários são permitidos com parênteses nas extremidades da parte local; por exemplo, john.smith(comment)@example.come (comment)[email protected]são equivalentes a "[email protected]", mas john.(comment)[email protected]seriam inválidos.
  • Os caracteres internacionais acima U+007F, codificados como UTF-8, são permitidos pela RFC 6531, embora os sistemas de correio possam restringir quais caracteres usar ao atribuir partes locais.

e para a parte global / domínio:

A parte do nome de domínio de um endereço de email deve estar em conformidade com diretrizes rígidas: deve corresponder aos requisitos de um nome de host, composto por letras, dígitos, hífens e pontos. Além disso, a parte do domínio pode ser um endereço IP literal, cercado por colchetes, como jsmith@[192.168.2.1]ou jsmith@[IPv6:2001:db8::1][…]

Fonte: Wikipedia

O que é válido?

Isso pode levar a endereços de email estranhos, mas válidos, como os seguintes:

  • [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

Fonte: php.net / autor [email protected] - exemplo corrigido pelo autor deste post

Limites

Também existem limites de tamanho local e de domínio:

O formato dos endereços de email é local-part@domainonde a parte local pode ter até 64 caracteres e o nome do domínio pode ter no máximo 253 caracteres - mas o máximo de 256 caracteres de um caminho para frente ou para trás restringe o endereço de email inteiro a não deve ter mais de 254 caracteres . [2] As definições formais estão na RFC 5322 (seções 3.2.3 e 3.4.1) e na RFC 5321 - com uma forma mais legível fornecida no informativo RFC 3696 [3] e nas erratas associadas .

Fonte: Wikipedia

Restrições do WordPress

E é isso que o WordPress verifica:

  • Teste o tamanho mínimo que o email pode ter: strlen( $email ) < 3
  • Teste para um caractere @ após a primeira posição: strpos( $email, '@', 1 ) === false
  • Teste para caracteres inválidos: !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local )
  • Teste para sequências de períodos: preg_match( '/\.{2,}/', $domain )
  • Teste para períodos iniciais e finais e espaços em branco: trim( $domain, " \t\n\r\0\x0B." ) !== $domain
  • Suponha que o domínio tenha pelo menos dois subs: $subs = explode( '.', $domain );e, em seguida,
    • 2 > count( $subs )
    • trim( $sub, " \t\n\r\0\x0B-" ) !== $sub
    • !preg_match('/^[a-z0-9-]+$/i', $sub )

Fonte: WP Core v4.0

Filtros e validação personalizada

Todos os casos mencionados acima serão acionados is_email()para retornar false. O resultado pode ser filtrado (um retorno de chamada pode ser anexado) e o filtro terá três argumentos, onde o último argumento é o motivo. Exemplo:

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

o que significa que você pode substituir os resultados retornados por verificações específicas.

Isso permite que você adicione verificações especiais, por exemplo, para permitir domínios de trema, partes de domínio somente de TLD, etc.

Conclusão

O WordPress é seguro para a maioria dos casos, mas mais restritivo, pois os servidores de email precisam ser compatíveis com RFC. Lembre-se de que nem todos os servidores de correio se alinham às diretrizes do RF 6531.

Editar

Lado engraçado: Existem duas funções relacionadas dentro ~/wp-includes/formatting: is_email()e sanitize_email(). Eles são praticamente a mesma função. Não sei por que alguém decidiu que seria uma boa ideia copiar o conteúdo da função de um para outro, em vez de apenas adicionar um como retorno de chamada aos filtros que o outro fornece. Como a v0.71 e a v1.5 são iguais, eu pessoalmente usaria a versão mais recente para obter uma string limpa. Observe que mesmo afirma que não é compatível com RFC.is_email() sanitize_email() is_email()

kaiser
fonte
Então, você está dizendo, em teoria, que existem endereços de e-mail completamente válidos de acordo com a RFC 6531, mas estes serão considerados inválidos pelo WordPress?
henrywright
Alguns sim. Por exemplo, domínios somente de TLD, domínios de trema, etc., como você pode ler no último parágrafo antes da conclusão da resposta. Por favor, leia a resposta novamente. Eu sei que é muito difícil de entender, mas vale a pena.
Kaiser
1
Na verdade, eu já li duas vezes, pois é algo que vale a pena entender! Obrigado por uma resposta tão detalhadas :)
henrywright
2

Desinfetar todas as coisas!

Uma das principais regras de segurança é nunca confiar na entrada do usuário. Em geral, não me importo com a implementação de is_email () ou qualquer outra função específica, ou se essa função faz algo perigoso com o que eu dou. Talvez a implementação mude algum dia. Quem sabe. Eu tenho que assumir que pode ser comprometido. A suposição deve sempre ser que a entrada do usuário seja ativamente hostil, duplamente para qualquer coisa eventualmente destinada a um banco de dados e higienizar cada bit de entrada do usuário antes de transferi-la para alguma função. Isso é apenas uma boa higiene geral de segurança.

JesseM
fonte
Acho que você acertou na cabeça quando disse que nunca sabe se a implementação será alterada. Pode ser bom não higienizar agora, mas quem sabe se isso mudará posteriormente?
henrywright