A few days ago, I tried emailing my mom using my usual mail account that I host on my domain. Verizon (her ISP) bounced my email back to me, claiming that my domain was a common spamming domain. I don’t send spam, of course, and I’ve owned my domain for over ten years without any problems.
If anyone is sending spam via my domain, it would be something like a hijacked mail script. I have a contact form on my website that uses the php mail function to send me mail, but I haven’t modified it in some time, so maybe it’s hijackable. I thought I’d paste it here and see if anyone noticed any red flags.
My HTML form:
<form name="contact" action="index.php" method="post" onsubmit="return valid(this)">
<p>This form sends me an email which contains the contact info you provide below.
I'll do my best to reply as soon as I can. Please provide a valid email
address if you expect a reply.<br />
<strong>All fields are required.</strong></p>
<p><label for="realname">From:</label><br />
<input name="realname" id="realname" type="text" class="form" title="Your name goes here" size="40" maxlength="16" />
<br /><br />
<label for="email">Your <strong>email</strong> address:</label><br />
<input title="Your email address goes here" class="form" type="text" size="40" name="email" id="email" />
<br /><br />
<label for="subject">Subject:</label><br />
<input title="Subject" class="form" type="text" size="40" name="subject" id="subject" />
<br /><br />
<label for="msg">Message:</label><br />
<textarea title="Type your message here"
class="form"
name="msg"
cols="40"
rows="10"
id="msg"></textarea>
<input type="hidden" name="token" value="<?= $better_token; ?>" />
<input type="test" name="info" class="catch" />
<br />
<input
type="submit"
value="Submit"
onclick="return check(this)"
alt="Submit"
name="image2"
class="submit" />
</p></form>
I took a glimpse, here are a few suggestions i put in the // comments
<?php
session_start();
// What's the point of forcing a blank field?
if (strlen($_POST['info']) != 0){
die('unable to process form');
}
if (isset($_POST['msg'])){
if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']){
// 1. You should place all validation at the top
// 2. Most importantly, You should use an email validator, so you know its a real email, ie:
$from = $_POST['email'];
$regexp = "/^[a-z0-9]+([_\\\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\\\.[a-z]{2,}$/i";
if (!preg_match($regexp, $from))
{
die('invalid email son');
}
$ip = $_SERVER['REMOTE_ADDR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
$host = gethostbyaddr($ip);
$send_to = "my@email.addy"; //actual email addy removed.
// You could combine these to save space
$sender = stripslashes($_POST['realname']);
$subject = stripslashes($_POST['subject']);
$msg = $_POST['msg'];
$message = $msg . "\
\
" . $ip . "\
" . $host . "\
" . $agent;
// You don't need to stripslashes the $messages variable,
// may as well delete this:
// $message = stripslashes($message);
$body = "Form mail from: " . $sender . " (" . $from . ")" . "\
\
" . $message;
?>
Also I wonder if you could show the code snippet where mail() function is actually called. The way it is set up could shed light on whether security breaches are likely.
// What’s the point of forcing a blank field? That’s a honeypot to stop spambots.
// 1. You should place all validation at the top
// 2. Most importantly, You should use an email validator, so you know its a real email, ie: Thanks. I have javascript in the form to do that, but I like your regex method better.
// You could combine these to save space
$sender = stripslashes($_POST[‘realname’]);
$subject = stripslashes($_POST[‘subject’]); Combine the subject and the sender?
$msg = $_POST[‘msg’];
$message = $msg . "
" . $ip . "
" . $host . "
" . $agent;
// You don’t need to stripslashes the $messages variable,
// may as well delete this:
// $message = stripslashes($message); Ah, ok. Thanks! I was just stripslashing everything.
Oops! Sorry, I have no idea how that got omitted!
At the bottom of the script above, it actually looks like this:
Don’t rely on javascript validation for security. It can help let a user know they made a mistake so they can fix it before submitting the form but it won’t keep your form secure. Do a search for “email header injection” and you should find lots of useful info. One thing I always wonder about is using the user supplied input for the “from”. I mean, it’s from your form, not them. Much better IMHO to put that info into the message body instead.
Because you are feeding user supplied email address ($from) directly to the fourth parameter of the mail() function without sanitizing it, your script is susceptible to email header injection attack. It’s highly probable that it’s exactly the hole which an attacker exploited to send out spams.
Validate the user input and also try to follow what Mittineague suggested.
// What’s the point of forcing a blank field? That’s a honeypot to stop spambots. hahaha a honeypot
// 1. You should place all validation at the top
// 2. Most importantly, You should use an email validator, so you know its a real email, ie: Thanks. I have javascript in the form to do that, but I like your regex method better.
It good to validate on the server too because some people have javascript off.
// You could combine these to save space
$sender = stripslashes($_POST[‘realname’]);
$subject = stripslashes($_POST[‘subject’]); Combine the subject and the sender?
[B][COLOR=Sienna]Oops, lol… I just ment put the string in one line like…
$subject = stripslashes($_POST[‘subject’]);
rather than
$subject = $_POST[‘subject’];
$subject = stripslashes($subject);[/COLOR][/B]
Yeah, it’s a useful method : add a field you hide with css in your form. Bots usually complete all fields so if the hidden one is not empty, a bot just sent it.
It won’t prevent any bot made to target your website but it’s better than nothing.
While hard-coding the headers will stop the “script-kiddies 101” spammers, if you don’t sanitize the input there are ways to spam from the message body as well. A little more complex to do, so it shouldn’t happen as often, but still possible if you use raw input values directly. Please be sure to research “email header injection” and sanitize your input values.