Email Injection: Possible Solution (PHP)
I'm hopeful that I've found the solution to the email injection problems that have begun to plague form-to-email applications across the web.
After an extensive amount of reading, I've learned that most of the abuse of these forms is achieved when a hacker is able to inject his own email headers into the messages generated by the form on a website. These injected headers are often in the form of additional cc: or bcc: which are then populated with hundreds or thousands of email addresses, and the form itself is then hijacked to send spam to those addresses.
The solution is simple in concept: prevent the insertion of new email headers. As a practical matter, this is not so straightforward, as some "solutions" can have unpleasant side-effects, like preventing the transmission of legitimate responses via the forms. However, the consensus seems to be that for a very simple form, which generates an email message to only one recipient, the following steps will prevent the vast majority of email injection attempts:
- Hard-code the recipient email address into the form; avoid making this a user-input variable
- Eliminate all unnecessary header data from the form - It's probably not important to have the name and email address of the person submitting the form show up in the header of the generated message, as long as you're receiving it in the body of the message
- Prevent the insertion of new email headers - This is most easily accomplished by stripping out linefeeds and carriage returns from the coding. This works because new email headers are identified by a preceding blank line. The downside to this is that you'll need to strip the linefeeds from your message body as well, which can lead to some hard-to-read email. However, you can mitigate this problem by coding in some data separators (like " | ").
- Test the form submissions for the presence of new and unwanted email headers, and if they're found, reject the submission. This is potentially tricky territory, as there are many different legitimate email headers. In addition, if you're not careful about how you specify those headers, you could reject legitimate submissions.
OK, that's the theory; here's the practice. Following is some PHP that can be placed inside the form processing code to accomplish #2 and #3 above. Included in the comments are the URLs for the origin of this code. I've implemented this approach on one test site and the spam immediately dropped from more than 50 per day to one...and I think that one was actually just a probe to see if the form was vulnerable to abuse.
// Following lines intended to prevent use of form by spammers
// by preventing the insertion of line feeds or carriage returns
// that might allow the creation of new email header data
// See www.anders.com,projects,sysadmin,formPostHijacking
$_POST['email'] = preg_replace("/\r/", "", $_POST['email']);
$_POST['email'] = preg_replace("/\n/", "", $_POST['email']);
$message = preg_replace("/\r/", "", $message);
$message = preg_replace("/\n/", "", $message);
foreach ( $_POST as $key => $value ) {
// Make form string lowercase to compare with the email_injection_filter function
strtolower($value);
// add current post var to $postVars
$postVars .= "$value ";
}
// Function from cyphix on
http://www.codingforums.com/showthread.php?
s=129cf1ecbeb511d27b759e97bff5e87c&t=67546
// Function prevents the insertion of additional email headers
function email_injection_filter($formInput) {
$injectionStrings = array("apparently-to",
"bcc",
"cc:",
"boundary=",
"charset",
"content-disposition",
"content-type",
"content-transfer-encoding",
"errors-to",
"in-reply-to",
"message-id",
"mime-version",
"multipart/mixed",
"multipart/alternative",
"multipart/related",
"reply-to",
"x-mailer",
"x-sender",
"x-uidl"
);
foreach ($injectionStrings as $spam)
{
if(eregi("$spam",$formInput)) {
die('Your message is deemed to be an attempt to hijack the originating email form, and has
been rejected.');
}
}
}
// actually check de vars
email_injection_filter($postVars);
Here's the usual disclaimer. I didn't write this code, and I can't guarantee that it will work for you, or that it will work, period. Use it as your own risk.
I've seen what I believe to be some benefit from it in one specific instance, but I'm sure that it can be improved. If you're fluent in PHP and can spot some things in this code that can make it work better, please feel free to share your suggestions and we'll try to create a better mousetrap...one that will ideally be completely fatal to the efforts of the jerks who are hijacking innocent websites for their own gain.
Following are some additional resources regarding email injection and how to fight it:
- Anders.com - This post is one of the earliest attempts to identify the problem and suggest solutions. From the same site, here's a summary of the issues.
- Secure PHP - More overview of the issues and possible solutions; mostly theory and requires a good understanding of PHP
- New York PHP - This user group article has a good explanation of the issues and some practical suggestions for addressing them.
- If you're using a PERL CGI mailer script, here's a source for an apparently secure version. In particular, if you're using ANY version of Matt Wright's FormMail.pl CGI script, you should immediately replace it with this new script. Why? Read this.
Technorati tag: Email Injection | Email Headers

YUK!!!!! Code!!!!!! YUK!!!!!!!!!
most definitely not my forte.
Posted by: shannon at December 8, 2005 02:57 PM