May 26 2007

Evitar Mail Injection em PHP

Category: PHPfabiomcosta @ 11:55

Bom pessoal, eu vou falar sobre um assunto que não é muito discutido e que muitos programadores até ignoram. O Mail Injection, que é uma forma de burlar um sistema de envio de e-mails em PHP, normalmente enviando spans a partir do servidor no qual o sistema esteja instalado. Isto pode denegrir a imagem de uma empresa, dentre outros problemas. Para saber mais, visite esta wiki que explica melhor.

Para começar vamos explicar o funcionamento da função mail(), a qual é nativa do php. Ela tem cinco parâmetros:

  • to > Endereço que irá receber o e-mail;
  • subject > Assunto da mensagem;
  • message > O corpo da mensagem;
  • additional_header > cabeçalhos adicionais(Com Cópia, Cópia Oculta, dentre outros cabeçalhos);
  • additional_parameters > usado para passar parametros para o programa que gerencia os e-mails.

Dentre estes campos, nós vamos nos preocupar com o to, o subject e o additional_header. Visto que os três são usados para incluir dados ao cabeçalho do e-mail.

Vamos a um exemplo, onde será mostrada a mensagem produzida pela execução da função mail:

mail('meiocodigo@gmail.com',$_GET['subject'],$_GET['message'],"From: ".$_GET['from']);

A função acima é largamente utilizada, visto que ele pega de um formulário o assunto, a mensagem e o remetente e envia por e-mail para um endereço fixo definido pelo progrador. Vamos supor que os valores de $_GET sejam como abaixo:

$_GET['subject'] = 'Post sobre Mail Injection'; $_GET['message'] = 'Pode tirar uma dúvida sobre o post sobre mail injection...'; $_GET['from'] = 'alguem@algumemail.com';

A mensagem produzida pela função supra-citada seria:

To: meiocodigo@gmail.com Subject: Post sobre Mail Injection From: alguem@algumemail.com

Pode tirar uma dúvida sobre o post sobre mail injection… Note que o formato gerado é:

To: $to Subject: $subject $additional_headers

$message

Até aqui está tudo certo, nenhum problema com o nosso código. Mas imagine se alguem insere o seguinte valor para Subject: ‘Assunto%0ACc: outro@email.com%0ABcc: maisoutro@email.com’. Essa String tem o mesmo valor que:

Assunto Cc: outro@email.com Bcc: maisoutro@email.com

Colocando isso no texto criado pela função mail nós temos:

To: meiocodigo@gmail.com Subject: Assunto Cc: outro@email.com Bcc: maisoutro@email.com From: alguem@algumemail.com

Pode tirar uma dúvida sobre o post sobre mail injection… Note que o arquivo gerado tem mais 2 itens no cabeçalho: um email para ser enviado como cópia; e outro como cópia oculta. É dessa forma que o formulário de e-mail é usado para fazer ataques de span. O detalhe é que o cabeçalho tem como separador a quebra de linha, ou seja, só é considerado um novo item do cabeçalho caso haja uma quebra de linha. Isso justifica o uso do %0A, que é o código hexadecimal da quebra de linha.

O que foi explicado acima se aplica a qualquer um dos três campos citados que fazem parte do cabeçalho.

Para resolver isso, eu criei uma função que checa se existem caracteres de quebra de linha nas strings de cabeçalho, retornando false, caso encontre:

function check_mail_injection($string){ if(strpos($string,'\n') !== false) return false; if(strpos($string,'\r') !== false) return false; if(strpos($string,'%') !== false) return false; return true; } Quero dedicar os créditos dessa função ao meu amigo Edson Aníbal da Superintendência de Informática da UFRN, que foi quem fez o procedimento, eu apenas encapsulei em uma função.

Vamos entender a função, ela pega uma $string, e verifica a existência de um caractere ‘\n’, ‘\r’ ou ‘%’. Os dois primeiros representam quebra de linha. E o ‘%’ pode ser usado para representar o código hexadecimal da quebra de linha.

Só mais um detalhe, não é recomendável aplicar essa função ao corpo da mensagem, visto que a mesma pode conter quebras de linha.

Espero ter sido claro. Qualquer dúvida coloca nos comentários.

Tags:

10 Responses to “Evitar Mail Injection em PHP”

  1. Fábio says:

    Muito bom o post, nunca tinha pensado nisso… vou tomar mais cuidado com os envios de e-mail agora.

  2. Matheus says:

    vou prestar atenção. valeu galera.

  3. Madson says:

    Eh Muito Bom!!!! Vcs me Salvaram legal, estava precisando disso!!

  4. Germano says:

    Ótimo post, só faço uma resalva de uma outra forma de mail injection q é na hora de um usuário preencher o cadastro de e-mail (pro exemplo ao se cadastrar em uma newsletter).

    Isso pq o primeiro parâmetro da função mail aceita vários emails separados por vírgula, então se ele colocar uma string com muitos email (provavelmente só pra ver o mal mesmo…) o servidor enviaria para todos esses emails.

    Pra resolver isso é só não inserir o registro onde são encotradas por exemplo duas @’s, q ficaria constatado dois emails, ou uma ou mais vírgulas…

    valew galera

  5. Micox says:

    Galera, passeei um pouco pelo blog novo aqui e a qualidade tá muito boa. Se for possível (e do agrado de vocês) gostaria de dar mais visibilidade a algumas materias aqui postando elas lá no fórum Webly: forum.ievolutionweb.com Claro que com os devidos créditos e link no início e final.

  6. Vinicius Mendes says:

    Obrigado a todos pelos comentários e pelo reconhecimento do trabalho.

    @Micox quanto a divulgar o conteúdo, fique a vontade, a única ressalva é a divulgação dos créditos, que por sinal você já falou que iria fazê-la.

  7. Junio says:

    Boa noite Vinicius,

    Estou estudando PHP, gostaria de saber o significado deste operador “!==” na função check_mail_injection, pois não tenho conhecimento.

    Agradeço desde já, Junio César Silva

  8. Vinicius Mendes says:

    Junio, o operador ‘!==’ significa realmente diferente. O PHP considera 0 igual a uma string vazia, ou a false. Então:

    0 != ” retorna false

    0 !== ” retorna true

  9. Junio says:

    Muito obrigado Vinicius, sua explicação foi de grande valia.Paz e saúde para ti.

  10. Luis says:

    Utilize expressões regulares, fica menor!

    preg_match(“/[\n\r%]/”,$string)