How to sanitze user input in PHP before mailing? - php

I have a simple PHP mailer script that takes values from a form submitted via POST and mails them to me:
<?php
$to = "me#example.com";
$name = $_POST['name'];
$message = $_POST['message'];
$email = $_POST['email'];
$body = "Person $name submitted a message: $message";
$subject = "A message has been submitted";
$headers = 'From: ' . $email;
mail($to, $subject, $body, $headers);
header("Location: http://example.com/thanks");
?>
How can I sanitize the input?

Sanitize the post variable with filter_var().
Example here. Like:
echo filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);

Since you're not building an SQL query or anything here, the only relevant validation that I can see for those inputs is an email validation for $_POST["email"], and maybe an alphanumeric filter on the other fields if you really want to limit the scope of what the message can contain.
To filter the email address, simply use filter_var:
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
As per Frank Farmer's suggestion, you can also filter out newlines in the email subject:
$subject = str_replace(array("\r","\n"),array(" "," "),$subject);

As others have noted, filter_var is great. If it's not available, add this to your toolchest.
The $headers variable is particularly bad security-wise. It can be appended to and cause spoofed headers to be added. This post called Email Injection discusses it pretty well.
filter_var is great, but another way to assure that something is an email address and not something bad is to use an isMail() function. Here's one:
function isEmail($email) {
return preg_match('|^[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]{2,})+$|i', $email);
};
So to use this, you could do:
if (isset($_POST['email']) && isEmail($_POST['email'])) {
$email = $_POST['email'] ;
} else {
// you could halt execution here, set $email to a default email address
// display an error, redirect, or some combination here,
}
In terms of manual validation, limiting the length using substr(), running strip_tags() and otherwise limiting what can be put in.

You need to remove any newlines from input provided by users in $headers, which gets passed to mail() ($email in your case)! See Email injection.
PHP should take care of sanitizing $to and $subject, but there are versions of PHP with bugs (Affected are PHP 4 <= 4.4.6 and PHP 5 <= 5.2.1, see MOPB-34-2007).

You can use the code from artlung's answer above to validate email..
I use this kind of code to prevent header injection ..
// define some mail() header's parts and commonly used spam code to filter using preg_match
$match = "/(from\:|to\:|bcc\:|cc\:|content\-type\:|mime\-version\:|subject\:|x\-mailer\:|reply\-to\:|\%0a|\%0b)/i";
// check if any field's value containing the one or more of the code above
if (preg_match($match, $name) || preg_match( $match, $message) || preg_match( $match, $email)) {
// I use ajax, so I call the string below and send it to js file to check whether the email is failed to send or not
echo "failed";
// If you are not using ajax, then you can redirect it with php header function i.e: header("Location: http://example.com/anypage/");
// stop the script before it reach or executing the mail function
die();
}
The mail()'s header filtering above is too strict, since some users may be using the filtered strings in their message without any intention to hijack your email form, so redirect it to a page that is explaining what kind of strings that is not allowed in the form or explain it on your form page.

Related

HTML php form validation and security

I have decided to remove my email address (an image) from my buisiness website and use a HTML form with reCAPTCHA to keep out the bots, so i have been learning some php.
The more i learn the less certain i am about the way forward.
I have two scenarios at the moment:
1 - I use somthing simple like:
<?PHP
$email_to_me = "my email address";
$name =$_POST['name'];
$email =$_POST['email'];
$comment =$_POST['comment'];
mail($email_to_me, $name, $comment, "from: .$email");
header("Location: contact.html");
?>
which will email me the message, redirect the user back to where they were but will not give the user a message sent confirmation.
2 - I use somthing like:
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$name = test_input($_POST["name"]);
$email = test_input($_POST["email"]);
$comment = test_input($_POST["comment"]);
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
Plus some field validation/error messages in the form.
Hopefully this will keep me on my HTML contact page and allow feedback to users of errors filling in fields and a confirmation can be message sent.
Is the second method safe against Cross-site scripting and other hacking methods?
I am getting my info from the www3schools.com.
I just want rid of the spam and virus attacks an email address on a website causes.
Any comments, thoughts, sites with relevent info, alternatives appreciated.
Thanks Uncoded
PHP do not allow site scriptings. Look for offsite domains in your javascript. Protect your data (which you store in db) with escape string and so on. If you need to solve some problem add your code in a question.

Ajax contact form and UTF-8

i'm using ajax contact form, downloaded from: http://youhack.me/2010/07/22/create-a-fancy-contact-form-with-css-3-and-jquery/
Everything works ok except UTF as i can't use cyrilic symbols when submitting.
The php:
$name = $_POST['name']; // contain name of person
$email = $_POST['email']; // Email address of sender
$web = $_POST['web']; // Your website URL
$body = $_POST['text']; // Your message
$receiver = "receiver#domain.com" ; // hardcorde your email address here - This is the email address that all your feedbacks will be sent to
if (!empty($name) & !empty($email) && !empty($body)) {
$body = "Name: {$name}\n\nSubject: {$web}\n\nMessage: {$body}";
$send = mail($receiver, 'Contact from domain.com', $body, "From: {$email}");
if ($send) {
echo 'true'; //if everything is ok,always return true , else ajax submission won't work
}
}
It uses jquery.validationEngine-en for validation.
My html already has "Content-Type" content="text/html; charset=utf-8" in header.
I'm new to php and jquery, so i would appriciate some guidance to make UTF-8 work when submitting.
Thanks :)
Edit: When i try to use cyrilic chars (čšćđ) on a required field i get ajax input error "Please use letters only". If i submit the form with cyrilic chars on a non-required field, i receive and email, all letters show ok except cyrilic, which are like this: Å¡.
Edit 2: When i set the recipient to gmail (webmail), cyrilic chars show up ok, except in one field, where Ajax doesnt let me use them (regex from Reinder answer).
When i set recipient in outlook (local) and submit the form, none of the cyrilic chars don't show up ok, example: ÄĹĄ oÄa ĹĄ ÄŽŠÄÄ
SOLVED Thanks to Reinder for guide and David! Will solve it today :)
having looked at the plugin you're using, I think this has to do with the validation regex inside jquery.validationEngine-en.js
when the validation is set to 'onlyLetter' it will check using
/^[a-zA-Z\ \']+$/
and none of your characters čšćđ are allowed here...
you need to create a language validation javascript for the language you're using and change that regular expression. For example, have a look at this post
The next thing is to check the encoding of your PHP file and your headers.
Place this at the top of your PHP code
header("Content-type: text/html; charset=utf-8");
Check if the values are correctly displayed when just outputting them in PHP, like so:
echo $name;
If they are correctly displayed in the browser and it's just the email that's incorrectly displaying the characters, then you need to pass an encoding header to the email too
example:
$headers = "From: $name <$email>\n";
$headers .= "Content-Type: text/plain; charset=UTF-8\n";
$body = "Name: {$name}\n\nSubject: {$web}\n\nMessage: {$body}";
$send = mail($receiver, 'Contact from domain.com', $body, $headers);
have a look at the mail function on the PHP.NET website
Rather than use the default PHP mail() function, I've found this come in handy when working with Japanese:
http://bitprison.net/php_mail_utf-8_subject_and_message

PHP: Email validation and accepting email address from a certain domain

I am currently working with AJAX/JS to have form without a button click or page refresh. The inquiry I have is in regards of email validation. Right now the PHP code checks if an email address is valid or not. I would like to only have it accept emails from a certain domain. How can I achieve through php to accept only email address from gmail? Example
PHP for validation of email:
if($_POST) {
$email = $_POST['email'];
if (preg_match('|^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$|i', $email)) {
echo ('<div id="email_input"><span id="resultval">'.$email.'</span></div>');
}
else {
echo ('<div id="email_input"><span id="resultval">Include a valid email address.</span></div>');
}
}
Php has an easy function to help you with checking if an email address is valid:
$isValid = filter_var($email, FILTER_VALIDATE_EMAIL);
To check if the email adress is a gmail address, the following would do the trick:
list ($user, $domain) = explode('#', $email);
$isGmail = ($domain == 'gmail.com');
Be careful with your regex, it won't validate all actual email addresses.
You have a built-in PHP function to check if an email is valid :
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
If this returns true, then you just have to check if the string ends with #gmail.com. Note that there may be some strange issues with this function, because email validation standards can be surprising.
If you really want a regex which validates all email addresses, here it is :
(?:[a-z0-9!#$%&'*+/=?^_{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
You should change you're regular expression to this
'|^[A-Z0-9._%+-]+#gmail\.com$|i'

Secure php email script

I want to use a php script to send emails from a html file on a website.
Would this php script be secure enough against hacking and spam?
<?php
$to = "emailto#site.com";
$subject = "Sent from site";
$email = $_POST['emailFrom'];
$message = $_POST['message'];
$email = filter_var($email , FILTER_SANITIZE_EMAIL);
$message = filter_var($message , FILTER_SANITIZE_EMAIL);
$message = $email . $message;
mail($to, $subject, $message, "From: webpage#site.com");
?>
FILTER_SANITIZE_EMAIL removes illegal email address characters from a string; this is, therefore not the best option for the contents of an email (however useful it may be for email addresses). Whilst removing HTML special characters is useful when preventing XSS attacks, it is worth noting that there are legitimate reasons to post < and > in messages (i.e. right now). Therefore it is better to convert these characters to their html entities.
I.e.
< would become <
and > would become >
So in order to change html characters to their entities replace:
$message = filter_var($message , FILTER_SANITIZE_EMAIL); with
$message = htmlspecialchars($message);
Other than that it looks good; but remember, in cases where a database is involved database sanitisation should also be added.

How is this contact us script vulnerable / being manipulated?

A client recently got a spam warning from their host.
I think I have pin pointed the issue to an old contact us form. Simple html on the front end and a simple PHP script on the back end.
if ($_POST['submit'] == "Send"){
//START SEND MAIL SCRIPT
$mail = $_POST['email'];
$to = "me#gmail.com";
$subject = "Message from Website Contact Us Form";
$headers = "From: Contact us Form <webmaster#website.co.uk>";
$message = "Message from Contact Us Form\n\n";
$message .= "\nName: " . $_POST['contactname'];
$message .= "\nEmail: " . $_POST['contactemail'];
$message .= "\nTelephone: " . $_POST['contactphone'];
$message .= "\n\n\nMessage:\n" . $_POST['contactmessage'];
if(mail($to,$subject,$message,$headers)) {
header('Location: http://www.website.co.uk/contact-us/?action=success');
}else{
header('Location: http://www.webisite.co.uk/contact-us/?action=fail');
}//END IF MAIL
}//END SCRIPT
I know the remedies to fix it such as sanitizing post vars properly, using captchas, using a hidden 'honeypot' blank field, js tricks etc etc (I also like the look of this script too http://www.alt-php-faq.com/local/115/)
But to help me understand what was going on I want to know how this script is being manipulated. A foreign script posting vars to it but how do they send email to anyone apart from
'me#gmail.com' or if they are forcing cc / bcc fields somehow why do I not get all spam as well??
Thanks
Line like this $message .= "\nName: " . $_POST['contactname']; can be dangerous.
If $_POST['contactname']='MegaSteve4 \r\nCc: email1#mail.com, email2#mail.com'; are set, 2 uses will get spam mail.
See carefully. Its appending more headers. In this case Cc. I am not sure if Cc is a raw email header. But I hope you get the idea.
You're not doing any escaping of the post data. That means that this form is vulnerable to injection attacks.
I couldn't tell you how they did it, but that's probably what happened.

Categories