Proper prevention of mail injection in PHP
To filter valid emails for use in the recipient email field, take a look at filter_var()
:
$email = filter_var($_POST['recipient_email'], FILTER_VALIDATE_EMAIL);
if ($email === FALSE) {
echo 'Invalid email';
exit(1);
}
This will make sure your users only supply singular, valid emails, which you can then pass to the mail()
function. As far as I know, there's no way to inject headers through the message body using the PHP mail()
function, so that data shouldn't need any special processing.
Update:
According to the documentation for mail()
, when it's talking directly to an SMTP server, you will need to prevent full stops in the message body:
$body = str_replace("\n.", "\n..", $body);
Update #2:
Apparently, it's also possible to inject via the subject, as well, but since there is no FILTER_VALIDATE_EMAIL_SUBJECT
, you'll need to do the filtering yourself:
$subject = str_ireplace(array("\r", "\n", '%0A', '%0D'), '', $_POST['subject']);
Suppose you you want to put the email address of the visitor in the optional header field like so:
$headers = "From: $visitorEmailAddress";
However, if
$visitorEmailAddress
contains
"[email protected]\n\nBCC:[email protected]"
you've made yourself a spam host, opening the door for mail injection. This is a very simple example, but creative spammers and malicious hackers can sneak potentially damaging scripts in your email, since email is sent as a plaintext file. Even attachments are converted plaintext, and they can easily send attachements by adding a mimetype content line.
If your form validation for the FROM and/or TO fields is OK, you have to look at the form validation for the body of the email. I'd strip out the '-=' and '=-' characters, and prevent users from typing plain HTML by using strip_tags()
.
Try this for a review of various options:
http://www.codeproject.com/Articles/428076/PHP-Mail-Injection-Protection-and-E-Mail-Validatio
It covers several options and tries to explain the benefits and risks of each.