I haven't had time to fully test it, but I thought I would post it for some feedback.
I'm sorry about the code not wraping in the post and it being sooooo wiiiiiiide, but I've given up trying to fix it.
This is the php code for _mail.php
Code: Select all
<?php
///////////////////////////////////////////////////////////////////////////
// CONFIGURATION SECTION
// READ THE FOLLOWING SECTIONS TO DECIDE HOW YOU WANT TO PROCESS YOUR FORM
//DEBUG MODE
//debug=1 to see what was sent to the mail() call. Use this if you don't get an email
//to check your input data fields.
$debug=0;
// protection level
// 0 = no protection
// 1 = stop Injection attempts only
// 2 = stop injection and text with links
// 3 = stop injection and sanitize all fields
// 4 = stop injection, reject text with links and sanitize all fields
$protect=3;
// Tracking
// 0=no tracking
// 1=include remote host's IP and forwarded IPs if using a proxy
$track=1;
//Blocked IP Addresses
//Put IPs in here of addresses that try to insert spam
//The ips in this array are just examples
//of how to add ip numbers.
// blocking=0; then no blocking takes place
// blocking=1; use the blockedip list to stop email
$blocking=0;
$blockedip=array("0.0.0.0","0.0.0.0");
//Sanitize Level
//
// 1= allow only numbers, space, and '-' (will alter email addresses)
// 2= allow only letters and spaces only (will alter email addresses)
// 3= allow only alphanumeric, spaces, period, and '-' (will alter email addresses)
// 4= allow only alphanumeric characters w/ basic punctuation and carriage returns (no: ( ) ; = ' " )
// 5= allow only alphanumeric w/ all punctuation and carriage returns
$sanitize=4;
// Your Email Information
// Configure the email address you want this form data sent to
// You can include a plain text field that usually holds your first and last name
$to="you@yourdomain.com"; // where to send the message
$to_name="First Last"; // plain text name with your first and last name
// Email Sent From You or User?
// Enable the last two lines in this section if you want the email
// to be formated as if it came from yourself and NOT the person filling out the form
// $from=$to; //from you to you
// $from_name=$to_name; //plain text field with your first and last name
// Field Maximium Character Lengths
// You can set the length of each input field
// to avoid any long messages from being inserted
// If you make these bigger, you need to edit the contact.html form
// because the input tags have a max size set on them as well.
// (The string size is also limited in the php code because spammers
// can bypass the contact.html form.)
$username_len=50;
$useremail_len=250;
$subject_len=150;
$comments_len=2000;
// Response Pages
// put the urls to your thank you page and if you are using
// the IP Blocking, include the url to your page to notify
// the user was blocked based on IP.
$thanksurl="http://www.yourdomain.com/yourpath/thanks.htm";
$blockurl="http://www.yourdomain.com/yourpath/blocked.htm";
// END OF CONFIGURATION SECTION
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//ERROR FUNCTIONS
//You can modify the text to display anything you want
// This is the message presented when a header injection is found
function errormsg()
{
echo "<br /><br />Sorry, the system failed to send message. Please avoid using the following:<br>to:<br //>bcc:<br />cc:<br />or any MIME type field like: content-type<br />or other non-ASCII characters<br><br>Press the back button and edit your message.";
echo '<br /><A HREF="javascript:history.back()">Back</A>';
return;
}
// This is the message presented when a http: link is found
function errormsg2()
{
echo "<br /><br />Sorry, the system failed to send message. Please avoid using links in your message or other non-ASCII characters<br /><br />Press the back button and edit your message.";
echo '<br /><A HREF="javascript:history.back()">Back</A>';
return;
}
// This is the message presented when a field is blank
function errormsg3()
{
echo "<br /><br />Sorry, the system failed to send message. A required field was left blank or the email address was not valid.";
echo '<br /><A HREF="javascript:history.back()">Back</A>';
return;
}
// END OF ERROR FUNCTIONS
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// MAIN CODE STARTS HERE
//
// the filter_var call is only avaiable in php 5.2.0+
// if this generates an error, upgrade your php build
// or use a regex filter to check for a valid email format
// there are many on the internet.
if(isset($_POST["Username"]) && isset($_POST["UserEmail"]) && filter_var($_POST['UserEmail'],FILTER_VALIDATE_EMAIL))
{
// Incoming input: Username,UserEmail,Comments,Subject
if($protect>0) //Check for injection
{
if(InjectionAttempt($_POST["Username"]) ) {
echo "Problem with Name Field<br>";
errormsg();
return;
}
if(InjectionAttempt($_POST["UserEmail"]) ) {
echo "Problem with your Email Field<br>";
errormsg();
return;
}
if(InjectionAttempt($_POST["Subject"]) ) {
echo "Problem with the Subject field<br>";
errormsg();
return;
}
}
//loop through IP list to block
//if you don't post error messages or redirect spam attempts
//you can add persistant spammers or abusers to the blocked list
//be careful because you can also block legit people sharing the ip
$block=0;
if($blocking)
{
foreach($blockedip as $hit)
{
if(strcmp($_SERVER['REMOTE_ADDR'],$hit)==0) $block=1;
// Since this could be a valid message, just tag it, but send
// the message with the blocked ip notice. If needed, you could put
// some code in here to redirect this user to a html page
// that tells them due to abuse they are blocked...
}
}
if($protect>2) // sanitize fields and truncate
{
$username=sanitize($sanitize,$username_len,$_POST['Username']);
$useremail=sanitize($sanitize,$useremail_len,$_POST['UserEmail']);
$subject=sanitize($sanitize,$subject_len,$_POST['Subject']);
$comments=sanitize($sanitize,$comments_len,$_POST['Comments']);
}
else
{
// To avoid users inserting really long strings, truncate them
$username=substr($_POST['Username'],$username,0,$username_len);
$useremail=substr($_POST['UserEmail'],0,$useremail_len);
$subject=substr($_POST['Subject'],0,$subject_len);
$comments=substr($_POST['Comments'],0,$comments_len);
}
//build the message body
$content = "\nNAME:\n".$username;
$content .= "\n\nEmail:\n".$useremail;
$content .= "\n\nMESSAGE:\n".$comments;
$content .= "\n\nSent:\n".date("l dS F Y h:i:s A"); // server time
$content .= "\nSent from: ".$_SERVER['REMOTE_ADDR'];
if($block) $content .= "\nIP BLOCKED\n"; // send message anyway, but indicate the user was told they were blocked
if(!(isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER']) && stristr($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST'])))
{
$content.= "Referrer information not available\n";
}
else
{
if(isset($_SERVER['HTTP_REFERER']))
$content .="\nReferring URL: ".$_SERVER['HTTP_REFERER'];
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
$content .="\nForwarded for:".$_SERVER['HTTP_X_FORWARDED_FOR'];
}
// If $from is not set, this means the email generated is supposed
// to appear as if it came from the person filling out the from.
// This makes it easy to reply back to them, however if the sanitization
// level is set to 1, 2 or 3 it will filter the email address.
// So in this case the email is made to look like it came from yourself.
// The reply fields will then be filled in with the hard coded $to email address.
if(!isset($from))
{
// the sanitization level is set<4 it will alter the $useremail address field
// in this case the from and reply addresses are set to your $to and $to_name fields
if($sanitize<4) $from=$useremail;
else $from=$to;
}
if(!isset($from_name))
{
// the sanitization level is set<4 it will alter the $useremail address field
// in this case the from and reply addresses are set to your $to and $to_name fields
if($sanitize<4) $from_name=$username;
else $from_name=$to_name;
}
//Build the email header
$eol="\r\n";
$headers = "Reply-To: ".$from_name."<".$from.">".$eol;
$headers.= "From: ".$from_name."<".$from.">".$eol;
$headers.= "Content-type: text/plain".$eol;
$headers.= "Message-ID: <".time()."-".$from.">".$eol;
$to=$to_name."<".$to.">".$eol;
if($protect==4 || $protect==2)
{
if(stristr($comments,"http")!=FALSE) // does http appear in the text?
{
errormsg2(); // this has a link reject.
return;
}
}
// SEND THE EMAIL
// Some servers do not let you set the $returnpath
// on these servers you will get a return path error
// You can comment out the next two lines and
// change $mail_sent=mail($to,$subject,$content,$headers);
ini_set(sendmail_from,$from); // the INI lines are to force the From Address to be used !
$returnpath="-f ".$from; // Forces the return path to be configured properly
$mail_sent = mail($to, $subject, $content, $headers, $returnpath);
if($debug)
{
echo "<hr />mail() Returned value mail_sent<br /><hr />".$mail_sent;
echo "<hr />To Field<br /><hr />".nl2br(htmlspecialchars($to));
echo "<br /><br /><hr />Subject<br /><hr />".nl2br(htmlspecialchars($subject));
echo "<br /><br /><hr />Content<br /><hr />".nl2br(htmlspecialchars($content));
echo "<br /><br /><hr />Headers<br /><hr />".nl2br(htmlspecialchars($headers));
echo "<br /><br /><hr />Return Path<br /><hr />".nl2br(htmlspecialchars($returnpath));
return;
}
//IS THE IP ON YOUR BLOCKED LIST?
//Tell them they are blocked (even though you allowed
//the message through) to discourage future attempts
if ($block==0) header('Location: '.$thanksurl);
else header('Location: '.$blockurl);
}
else
{
//no username or email address was given
errormsg3();
}
//FUNCTION TO CHECK FOR INJECTION ATTACKS
function InjectionAttempt($input) // this detects any injection characters or other odd non-ascii characters
{
// list of blocked header injection strings
$stoplist = array
("to:",
"cc:",
"bcc:",
"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($stoplist as $find)
{
if(stripos(" ".$input, $find)) return 1;
}
// block control codes and UTF codes like NEL, FF, LS, PS, CR, LF
// %00-%1F that can cause injection fields to occur
if (preg_match('/[\x00-\x1F\x7F]/',$input) ||
preg_match("/(%[0-1][0-9A-Fa-f])/i", $input) ||
preg_match("/\x{000A}/ui",$input) ||
preg_match("/\x{000B}/ui",$input) ||
preg_match("/\x{000C}/ui",$input) ||
preg_match("/\x{000D}/ui",$input) ||
preg_match("/\x{0085}/ui",$input) ||
preg_match("/\x{2028}/ui",$input) ||
preg_match("/\x{2029}/ui",$input))
{
return 1; // Injection found
}
else
{
return 0;
}
}
//FUNCTION TO SANITIZE DATA
function sanitize($dtype, $dlen=0, $data)
{
// Used to remove bad characters, tags, javascripts, etc. from $data string.
// will also truncate to $dlen if not set to 0;
// Remove special characters
$data = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $data);
$data = preg_replace("|\.\./|",'', $data); // stop directory traversal
$data = preg_replace("/--/",' - ', $data); // stop mySQL comments
$data = preg_replace("/%3A%2F%2F/",'', $data); // stop B64 encoded '://'
// Remove Null Characters
// This prevents sandwiching null characters
// between ascii characters, like Java\0script.
$data = preg_replace('/\0+/', '', $data);
$data = preg_replace('/(\\\\0)+/', '', $data);
// Validate standard character entities
// Add a semicolon if missing. We do this to enable
// the conversion of entities to ASCII later.
$data = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u',"\\1;",$data);
// Validate UTF16 two byte encoding (x00)
// Just as above, adds a semicolon if missing.
$data = preg_replace('#(&\#x*)([0-9A-F]+);*#iu',"\\1\\2;",$data);
// URL Disable
// Just in case stuff like this is submitted:
// <a href="http://blah.blah.com">Google</a>
// also stops HEX injected links
// or any http: is located, disable it by removing the http: and inserting URL:
if(stristr($data,"http:")!=FALSE) // does http appear in the text?
{
$data=str_ireplace("http:", "URL:", $data);
}
// Convert character entities to ASCII
// Only convert entities that are within tags since
// these are the ones that will pose security problems.
if (preg_match_all("/<(.+?)>/si", $data, $matches))
{
for ($i = 0; $i < count($matches['0']); $i++)
{
$data = str_replace($matches['1'][$i],
html_entity_decode($matches['1'][$i], ENT_COMPAT, $charset), $data);
}
}
// Convert all tabs to spaces
// This prevents strings like this: ja vascript
// Note: we deal with spaces between characters later.
$data = preg_replace("#\t+#", " ", $data);
// Makes PHP tags safe
// Note: XML tags are inadvertently replaced too:
// <?xml
$data = str_replace(array('<?php', '<?PHP', '<?', '?>'), array('<?php', '<?PHP', '<?', '?>'), $data);
// Compact any exploded words
// This corrects words like: j a v a s c r i p t
// They are compacted back to their correct state.
$words = array('javascript', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
foreach ($words as $word)
{
$temp = '';
for ($i = 0; $i < strlen($word); $i++) {
$temp .= substr($word, $i, 1)."\s*";
}
$temp = substr($temp, 0, -3);
$data = preg_replace('#'.$temp.'#s', $word, $data);
$data = preg_replace('#'.ucfirst($temp).'#s', ucfirst($word), $data);
}
// Remove disallowed Javascript in links or img tags
$data = preg_replace("#<a.+?href=.*?(alert\(|alert&\#40;|javascript\:|window\.|document\.|\.cookie|<script|<xss).*?\>.*?</a>#si", "", $data);
$data = preg_replace("#<img.+?src=.*?(alert\(|alert&\#40;|javascript\:|window\.|document\.|\.cookie|<script|<xss).*?\>#si","", $data);
$data = preg_replace("#<(script|xss).*?\>#si", "", $data);
// Remove JavaScript Event Handlers
// It removes the event handler and
// anything up to the closing >
$data = preg_replace('#(<[^>]+.*?)(onabort|onactivate|onafterprint|onafterupdate|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditfocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror|onerrorupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizeend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|onstop|onsubmit|onunload)[^>]*>#iU',"\\1>",$data);
// Sanitize HTML elements
// If a tag containing any of the words in the list
// below is found, the tag gets converted to entities.
// So this: <blink>
// Becomes: <blink>
$data = preg_replace('#<(/*\s*)(alert|vbscript|javascript|applet|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|layer|link|meta|object|plaintext|style|script|textarea|title|xml|xss|lowsrc)([^>]*)>#is', "<\\1\\2\\3>", $data);
// Sanitize scripting elements
// Similar to above, only instead of looking for
// tags it looks for PHP and JavaScript commands
// that are disallowed. Rather than removing the
// code, it simply converts the parenthesis to entities
// rendering the code un-executable.
// For example: eval('some code')
// Becomes: evalsome code
$data = preg_replace('#(alert|cmd|passthru|eval|exec|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2(\\3)", $data);
// Final clean up
// This adds a bit of extra precaution in case
// something got through the above filters
$junk = array(
'document.cookie' => '',
'document.write' => '',
'window.location' => '',
"javascript\s*:" => '',
"Redirect\s+302" => '',
'<!--' => '<!--',
'-->' => '-->'
);
foreach ($junk as $key => $val) {
$data = preg_replace("#".$key."#i", $val, $data);
}
// Truncate if input string is longer than specified
if($dlen != '0'){
$data = substr($data, 0, $dlen);
}
if($dtype == '1'){
// allow only numeric characters, space, period, and '-'
$data = preg_replace("/[^0-9\-\ \.]/",'', $data);
}
if($dtype == '2'){
// allow only alpha characters, '_' and space
$data = preg_replace("/[^a-zA-Z~\ \_]/",'', $data);
}
if($dtype == '3'){
// allow only alphanumeric characters, space, '_', period, colon, and '-'
$data = preg_replace("/[^0-9a-zA-Z~\-\ \.\:\_]/",'', $data);
}
if($dtype == '4'){
// allow only alphanumeric characters w/ punctuation + carriage returns (no ; = ' " ( ) )
$data = preg_replace("|[^0-9a-zA-Z~@#$%:_, \\n\\\!\^&\*\-\+\.\?\/]|",'', $data);
}
if($dtype == '5'){
// allow only alphanumeric characters w/ punctuation + carriage returns
$data = preg_replace("|[^0-9a-zA-Z~@#$%=:;_, \\n\\\!\^&\*\(\)\-\+\.\?\/\'\"]|",'', $data);
}
$data = trim($data);
return $data;
}
?>Code: Select all
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta http-equiv="Content-Language" content="en-us">
<title>Contact Us</title>
<meta name="description" content="Use this form to send an email message.">
</head>
<body "bgcolor="#FFFFFF" text="#000000" link="#993333" vlink="#333399" alink="#006633">
<div align="center">
<center>
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" width="600">
<tr>
<td valign="top" width="5" style="border-right-style:none; border-right-width:medium; border-top-style:none; border-top-width:medium; border-bottom-style:none; border-bottom-width:medium"></td>
<td valign="top" height="100%" style="border-right-style:none; border-right-width:medium; border-top-style:none; border-top-width:medium; border-bottom-style:none; border-bottom-width:medium" width="452">
<p>Send a message and we'll get back to you as soon
as possible.</p>
<form name="Contact" action="_mail.php" method="POST">
<table id="table1">
<tr>
<td width="83"><font face="trebuchet ms,arial,helvetica">Your Name:</font></td>
<td><font face="trebuchet ms,arial,helvetica">
<input type="text" size="50" maxlength="50" name="Username"></font></td>
</tr>
<tr>
<td width="83"><font face="trebuchet ms,arial,helvetica">Your Email: </font></td>
<td><font face="trebuchet ms,arial,helvetica">
<input type="text" size="50" maxlength="250" name="UserEmail"></font></td>
</tr>
</table>
<table id="table2">
<tr>
<td width="85"><font face="trebuchet ms,arial,helvetica">Subject: </font></td>
<td><font face="trebuchet ms,arial,helvetica">
<input type="text" size="50" maxlength="150" name="Subject"></font></td>
</tr>
</table><font face="trebuchet ms,arial,helvetica">
<p><strong>Enter your message in the space provided below:</strong></p>
<dl>
<dd>
<textarea name="Comments" rows="5" cols="50" style="text-align: left; line-height: 100%" maxlength="2000"></textarea></dd>
<dd> </dd>
</dl>
<p align="center">
<input type=SUBMIT value="Send Message">
<input type="RESET" value="Clear Form"></p>
</form>
</font></td>
</tr>
</table></body>
</html>