Best PHP security technique for when working with forms.

I learning about PHP security and in the book PHP 5 advanced by Larry Ullman It says to lookout for and replace '\n' and '\r'.

Below is how I have gone about this. Is this the best way to go? Is it needed? Is there a better way.

I ask because I have a few PHP books and none of them seem to do anything like this.

Thanks,
Daniel.
// Check that the conSubject field is less than 100 characters
// Check that the conSubject field does not contain '\n' or '\r'
$pos = strpos($conSubject, '\n');
$pos = !$pos ? strpos($conSubject, '\r') : $pos; 
if (strlen($conSubject) > 100 || !($pos === false)) {
  $errors[] = 'The name field must be 100 characters or less and must consist of letters or spaces only';
}

Open in new window

LVL 4
iDeejAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Matthew KellyCommented:
Best practice is to put validation code into a function and then call it when you need it on variables. Here are some more input validations I typically do: http://www.matthewstevenkelly.com/blog/kb/php-input-validation.html

The newline characters in fields that do not allow newlines is a good check I never thought of before. It wouldn't be a bad thing to check.


The section you are referring to is:

http://www.peachpit.com/articles/article.aspx?p=712187
"Avoiding Mail Abuses

A security concern exists in any Web application that uses the mail() function with form data. For starters, if someone enters their "to" email address as someone@example.com,someone.else@example.com, you'll now be sending two emails. If a malicious user enters 500 addresses (perhaps by creating their own form that submits to your same page), you're now sending out spam! You can avoid this by using regular expressions to guarantee that the submitted value contains just one address. Or you could search for a comma in the submitted email address, which wouldn't be allowed. But that won't solve the problem entirely.

Although the mail() function takes separate arguments for the "to" address, "from" address (or other additional headers), subject, and body, all four values are put together to create the actual message. By submitting specifically formatted text through any of these inputs, bad people can still use your form to send their spam. To guard against this, you should watch for newline (\n) and carriage returns (\r) within the submitted data. Either don't send emails with these values or replace them with spaces to invalidate the intended message format. You should probably also make sure that you (or someone involved with the site) receives a copy of every email sent so that close tabs can be kept on this area of the server."
$errors = checkForNewLines($conSubject, 100);
if($errors != "")
{
 $conSubject = "";
 echo $errors;
}
else 
{
 // continue code
}

function checkForNewLines($data, $datalen)
{
  $errors = "";
  // Check that the conSubject field is less than 100 characters
  // Check that the conSubject field does not contain '\n' or '\r'
  $pos = strpos($conSubject, '\n');
  $pos = !$pos ? strpos($conSubject, '\r') : $pos; 
  if (strlen($conSubject) > $datalen || !($pos === false)) {
    $errors = 'The name field must be '.$datalen.' characters or less and must consist of letters or spaces only';
  }
  return $errors;
}

Open in new window

HackneyCabCommented:
Form data can contain anything, so there's no single formula for validating form data. The questions to ask are:

* what values are useful to my script (for instance, no point allowing newlines in a "username" or "phone number" field);
* what am I going to do with the user-supplied data (dump it into an HTML page / store it in a MySQL database, etc).

If you're going to dump user-supplied data into an HTML page, you must use htmlspecialchars (and make sure to use the ENT_QUOTES flag) to avoid any embedded markup or scripting in the user-supplied data being treated as part of your page.

If you're going to store user-supplied data into a MySQL database, see the real_escape_string function:

http://php.net/manual/en/function.mysql-real-escape-string.php

which escapes quotes and backslashes so that user-supplied data cannot inject SQL statements into your database queries.
iDeejAuthor Commented:
Ok so wrapping this up, Larry in his book says to take out or replace \r and \n with emails.

Could you please tell me what problems \r and \n could cause?

And instead of the lengthy code I used above could I just use mysql_real_escape_string to render \r ineffective?

Protecting & Securing Your Critical Data

Considering 93 percent of companies file for bankruptcy within 12 months of a disaster that blocked access to their data for 10 days or more, planning for the worst is just smart business. Learn how Acronis Backup integrates security at every stage

iDeejAuthor Commented:
Some great information by the way. Very much appreciated!
HackneyCabCommented:
Emails use headers (which state where to send the message, whether to use MIME multipart format, and so on) and headers all come at the top of the email message, with one \r\n (carriage return followed by newline) between each header.

If you allow user-data to go straight into email headers (and remember that the subject value goes straight into the email headers) without checking that it contains no \r or \n characters, you can allow rogue users to inject email headers into your outgoing email. This can, believe it or not, have the effect of completely replacing your email message with a message of their own, and a recipient list of their choosing. (Search for email header injection to find out more.)

So if your user-supplied data is going into email headers (and remember that that includes the email subject) you need to either check that no carriage returns or line feeds are present, or escape them carefully. (To be honest, there should never be newlines and such in an email subject, so it only really makes sense to bark at the user or terminate script execution.)

To check for newlines and carriage returns, try this:

if(preg_match(';[\n\r];', $user_supplied_string) == 1) {
    // User has likely tampered with our site to submit newlines or carriage returns.
    // This can't be done using our HTML form, so suspect foul play.
    // Terminate execution.
    die();
}

You might also want to use trigger_error to log the attempt, but this will get boring after a while because malware bots roam the web spamming HTML forms with garbage values to see if they can find weak spots, so your error logger would be kept busy.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
iDeejAuthor Commented:
Thank you kindly. Very helpful.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Software

From novice to tech pro — start learning today.