Os cuidados que você precisa tomar no PHP pra não acabar com um problema desses é bem simples. Vamos ver passo a passo como normalmente é feito o envio de emails através do PHP e onde podemos melhorá-lo.
Um formulário típico de contato de algum site, poderia ter a forma abaixo:
<form action="envia.php" method="post">
Nome: <input type="text" name="nome" /><br />
Email: <input type="text" name="email" /><br />
Mensagem: <textarea name="mensagem"></textarea><br />
<input type="submit" />
</form>
Ou seja, com o formulário acima o usuário coloca seu nome, seu email e a mensagem que deseja enviar. Ao se clicar no botão de submit, os dados são passados para o script envia.php, que tem a tarefa de enviar um email com a mensagem do usuário.
Função mail() do PHP
<?php
$para = "equipe@site.com.br";
$assunto = "Contato do site";
$msg = $_POST['mensagem'];
$headers = "From: {$_POST['nome']} <{$_POST['email']}>";
mail($para, $assunto, $msg, $headers);
?>
Tudo muito bonito. O usuário envia seu nome, email e a mensagem e o script PHP manda um email para equipe@site.com.br com o conteúdo do email. Estaria perfeito se não fosse pela montagem do cabeçalho From. O grande problema está em não tratar esses dados que foram enviados pelo usuário. Se o usuário faz o envio normalmente, teríamos um email mais ou menos assim (estou ignorando alguns cabeçalhos para simplificar o exemplo):
From: Jason Bonatelli <jason@bonatelli.net>
To: equipe@site.com.br
Subject: Contato do site
Olá, aqui vai a minha mensagem.
Nesse caso postei meu nome, meu email e a mensagem acima é enviada para a equipe do site. Porém como o usuário tem o controle sobre o que entra no cabeçalho da mensagem, ele pode ser um pouco sacana e colocar uma quebra de linha no nome dele, com algumas coisas depois.
Quebra de linha
Por exemplo, se no lugar do meu nome eu coloco "Buy Viagra <xx@xx.com>\nBcc: <email1@dominio1.com>, <email2@dominio2.com>, <email3@dominio3.com>, " e na mensagem eu coloco algo sobre venda de viagra, teríamos o seguinte email montado:
From: Buy Viagra <xx@xx.com>
Bcc: <email1@dominio1.com>, <email2@dominio2.com>, <email3@dominio3.com>, <bruno@lustosa.net>
To: equipe@site.com.br
Subject: Contato do site
Compre Viagra, baratinho!!
Isso foi apenas um exemplo, mas dá pra combinar outras técnicas e conseguir por exemplo sobrescrever o assunto da mensagem. E hoje em dia já existem robôs vasculhando formulários de sites buscando por vulnerabilidades desse tipo.
Aconteceu em um código antigo da empresa onde estou trabalhando agora. Começamos a entrar em algumas listas negras e sem entender o porque. Quando fomos verificar a fila de emails esperando pra sair do servidor, eram mais de 30 mil spams sobre todo tipo de lixo. E vasculhando os logs do servidor web, chegamos ao script culpado.
É claro que isso NÃO É um problema do PHP. O PHP é tão seguro quanto uma pistola. Se o programador decide dar um tiro no próprio pé, não dá pra colocar a culpa na arma, não é? Esse é apenas mais um exemplo do tipo de problema que podemos enfrentar quando não validamos os dados enviados pelo usuário.
Sempre que qualquer informação for enviada de um lugar não confiável, essa informação deve ser checada. Uma simples verificação em $_POST['nome'], buscando por quebras de linha ou em $_POST['email'], verificando se se trata de um email válido, já resolveria esse problema.
A grande maioria dos problemas que vemos divulgados diariamente em todo tipo de script PHP se baseia no fato de que os programadores não tem o hábito de programar pensando em segurança e não fazem as checagens mais básicas, deixando os scripts vulneráveis a ataques como o descrito acima e outros.