Prevent Contact Form Spam Email Header Injection

By
February 28, 2008 | Thoughts from the team, Tutorials

A common technique employed by spammers to send large quantities of email is through the use of unsecured web forms like contact forms. The vulnerability they exploit is a form of Header Injection. There are several basic steps you can take to secure your web forms and prevent spam from originating from your website.

A Basic Contact Form

Here is a very basic contact form and script to send emails. This example uses PHP however the techniques are equally applicable to any other web programming language such as Perl, Python, ASP.NET, Ruby etc

index.html

<form name="contact" action="mailer.php" method="POST">

   <label>From:</label> <input type="text" name="email" /><br />
   <label>Subject:</label> <input type="text" name="subject" /><br />
   <label>Message:</label> <textarea name="body"></textarea><br />
   <input type="submit" name="Submit" value="Submit" />

</form>

mailer.php

<?php
   $to = "adam@www.stormconsultancy.co.uk";
   $from = $_POST['email'];
   $subject = $_POST['subject'];
   $body = $_POST['body'];

   $headers = "From: $from\r\n";
   $headers .= "Reply-to: $from\r\n";

   // send mail
   if (mail($to,$subject,$body,$headers)){
     echo "Message sent successfully";
   }else{
     echo "Error: Sending your message failed";
   }
?>

Improving Security

Now we will go through a few simple steps to improve the security.

Prevent Direct Access to the Mail Script

<?php
   if(isset($_POST['Submit'])) {
     //existing code
   }else{
     die("Direct access not allowed!");
   }
?>

By preventing direct access to the script, the spammer must create a fake POST request that mimics the form submission. This is more difficult than simply calling the script and the more barriers we can build up, the more secure our form will be.

Remove Line Endings from Input

In our original example, we took the $FROM address straight from the form and used it to set the ‘Reply-To:’ and ‘From:’ headers. Notice that in between each of the headers we have added ‘\r\n’. This is used as a delimiter to indicate the end of one header and the beginning of the next. This is a window of opportunity for an attacker. If they can craft the $FROM variable so it looks like ‘from@domain.com\r\n CC: victim@domain.com’ then a CC header will also be set and the message will be CC’d to the victims address.

We can do some simple filtering on all of our input variables to prevent this from happening:

$from = preg_replace("([\r\n])", "", $_POST['email']);
$subject = preg_replace("([\r\n])", "", $_POST['subject']);

Remove Header Injections

$match = "/(bcc:|cc:|content\-type:)/i";
if (preg_match($match, $from) ||
    preg_match($match, $subject) ||
    preg_match($match, $body)) {
  die("Header injection detected.");
}

This snippet of code should be inserted before we start to build up the $header variable and provides another layer of protection by removing any strings that look like mail headers.

These 3 simple steps will provide a good level of security for your contact form and prevent you being the source of spam. We suggest you also read the SecurePHP article for a more complete explanation of email header injection, how it’s done and other ways prevent it.

More like this