0

I came across a ready-made contact form on TutWow from 2012. It uses Douglas Lovell's PHP e-mail validation from 2007 that checks whether the email field is valid (even queries DNS servers to see if the domain is valid). Being 6 years old, the question arises — is it still relevant?

In general, what should one usually look for in a mail() script for it to be secure but have a minimal footprint? And does Mr. Lovell's script, combined with TutWow's PHP tie-ins, qualify?

Here is the PHP of the combination:

<?php

// Clean up the input values
foreach($_POST as $key => $value) {
  if(ini_get('magic_quotes_gpc'))
    $_POST[$key] = stripslashes($_POST[$key]);

  $_POST[$key] = htmlspecialchars(strip_tags($_POST[$key]));
}

// Assign the input values to variables for easy reference
$name = $_POST["name"];
$email = $_POST["email"];
$message = $_POST["message"];

// Test input values for errors
$errors = array();
if(strlen($name) < 2) {
  if(!$name) {
    $errors[] = "You must enter a name.";
  } else {
    $errors[] = "Name must be at least 2 characters.";
  }
}
if(!$email) {
  $errors[] = "You must enter an email.";
} else if(!validEmail($email)) {
  $errors[] = "You must enter a valid email.";
}
if(strlen($message) < 10) {
  if(!$message) {
    $errors[] = "You must enter a message.";
  } else {
    $errors[] = "Message must be at least 10 characters.";
  }
}

if($errors) {
  // Output errors and die with a failure message
  $errortext = "";
  foreach($errors as $error) {
    $errortext .= "<li>".$error."</li>";
  }
  die("<span class='failure'>The following errors occured:<ul>". $errortext ."</ul></span>");
}

// Send the email
$to = "YOUR_EMAIL";
$subject = "Contact Form: $name";
$message = "$message";
$headers = "From: $email";

mail($to, $subject, $message, $headers);

// Die with a success message
die("<span class='success'>Success! Your message has been sent.</span>");

// A function that checks to see if
// an email is valid
function validEmail($email)
{
   $isValid = true;
   $atIndex = strrpos($email, "@");
   if (is_bool($atIndex) && !$atIndex)
   {
      $isValid = false;
   }
   else
   {
      $domain = substr($email, $atIndex+1);
      $local = substr($email, 0, $atIndex);
      $localLen = strlen($local);
      $domainLen = strlen($domain);
      if ($localLen < 1 || $localLen > 64)
      {
         // local part length exceeded
         $isValid = false;
      }
      else if ($domainLen < 1 || $domainLen > 255)
      {
         // domain part length exceeded
         $isValid = false;
      }
      else if ($local[0] == '.' || $local[$localLen-1] == '.')
      {
         // local part starts or ends with '.'
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $local))
      {
         // local part has two consecutive dots
         $isValid = false;
      }
      else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
      {
         // character not valid in domain part
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $domain))
      {
         // domain part has two consecutive dots
         $isValid = false;
      }
      else if(!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',
                 str_replace("\\\\","",$local)))
      {
         // character not valid in local part unless
         // local part is quoted
         if (!preg_match('/^"(\\\\"|[^"])+"$/',
             str_replace("\\\\","",$local)))
         {
            $isValid = false;
         }
      }
      if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")))
      {
         // domain not found in DNS
         $isValid = false;
      }
   }
   return $isValid;
}

?>
Baumr
  • 6,124
  • 14
  • 37
  • 63
  • 1
    From my experience you can lose valid addresses by querying dns. be afraid. – Itai Sagi Jan 13 '13 at 17:38
  • 1
    Won't speak to the security aspect, but potentially making five regex calls AND checking the dns??? That's going to be slow as molasses. –  Jan 13 '13 at 17:38

3 Answers3

1

Perhaps the safest way would be to send the sender an email asking them to confirm that they did indeed send the message. Also, to prevent your contact form being turned into a spam system, limit the number of contact forms each IP address can submit to a reasonable number, probably 1 every 24 hours, assuming replies will be done through regular email.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Great ideas. Yup, replies done via regular email. Do you know of a ready-made script that features all of this? – Baumr Jan 13 '13 at 17:52
1

This validation is not the best I have seen. What I notice by quickly looking at it is:

  • It uses htmlspecialchars() without the encoding argument
  • It uses strip_tags() for a reason I fail to see
  • It uses strlen instead of mb_strlen
  • It is vulnerable to header injection
  • And the mail validation is not the best I have seen
  • There is no CSRF token
  • Theer is no captcha
Community
  • 1
  • 1
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
0

Through all my projects, I have found this guide to be the most helpful security-wise.

It has many sections including Form processing, Databases and SQL, Sessions, and more.

user1909426
  • 1,658
  • 8
  • 20