Forum Moderators: coopster

Message Too Old, No Replies

Writing A Secure Form

         

ramoneguru

9:53 pm on Oct 27, 2006 (gmt 0)

10+ Year Member



Ok, I have a form that collects the following:
First name
Last name
Phone number
Birthdate
Address

I need this to provide 'minimal' security and here's what I have:

1. Check the POST value to make sure it came from the correct server (anyone know how that is done exactly?)
2. Pass each through a regular expression checking for correct format and character class.

Am I missing anytihing?
--Nick

henry0

10:17 pm on Oct 27, 2006 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You are missing at least using
htmlentities() with any form input not going directly in your db

and for DB
(you might for info purpose check your php.ini
for magic_quotes on or not
but the following function takes care of that
(from the PHP manual)

function CleanDb($value)
{
// Stripslashes
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
// Quote if not a number or a numeric string
if (!is_numeric($value)) {
$value = "'" . mysql_real_escape_string($value) . "'";
}
return $value;
}

Further a search here for "Validating forms"
will return plenty goodies :)

eelixduppy

11:13 pm on Oct 27, 2006 (gmt 0)




Check the POST value to make sure it came from the correct server (anyone know how that is done exactly?)

You could read the $_SERVER['HTTP_REFERER'] [us3.php.net] global to see where it's coming from, but this isn't entirely foolproof.

From the manual:


'HTTP_REFERER'
The address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.

Other than that you can use simple anti-spam techniques on the form itself such as a sum of two random numbers that a user has to type into an input. There are, again, many threads on this subject. Here's one such example: [webmasterworld.com...]

Best of luck!

jatar_k

4:29 pm on Oct 28, 2006 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



also take a look at these

PHP Security [webmasterworld.com]
PHP Peer Code Review [webmasterworld.com]

bluesmandeluxe

8:35 pm on Oct 31, 2006 (gmt 0)

10+ Year Member



>>You are missing at least using
htmlentities() with any form input not going directly in your db<<

Unfortunately, if you are on a server using php 4.3 or less, you are out of luck. The htmlentities() function is for php 4.4 or higher.

I discovered this the hard way and am in the process of changing to an upgraded server.

And htmlentities() is just a start. It has glaring holes of its own.

This is a beautiful enhanced filter I found at [us2.php.net ] see Cameron's posting may 5, 2006 (am I allowed to post code?), it is intended as a super htmlentities() - this includes all of his comments:


<?php
// Convert str to UTF-8 (if not already), then convert that to HTML named entities.
// and numbered references. Compare to native htmlentities() function.
// Unlike that function, this will skip any already existing entities in the string.
// mb_convert_encoding() doesn't encode ampersands, so use makeAmpersandEntities to convert those.
// mb_convert_encoding() won't usually convert to illegal numbered entities (128-159) unless
// there's a charset discrepancy, but just in case, correct them with correctIllegalEntities.

function makeSafeEntities($str, $convertTags = 0, $encoding = "") {
if (is_array($arrOutput = $str)) {
foreach (array_keys($arrOutput) as $key)
$arrOutput[$key] = makeSafeEntities($arrOutput[$key],$encoding);
return $arrOutput;
}
else if (!empty($str)) {
$str = makeUTF8($str,$encoding);
$str = mb_convert_encoding($str,"HTML-ENTITIES","UTF-8");
$str = makeAmpersandEntities($str);
if ($convertTags)
$str = makeTagEntities($str);
$str = correctIllegalEntities($str);
return $str;
}
}
// Convert str to UTF-8 (if not already), then convert to HTML numbered decimal entities.
// If selected, it first converts any illegal chars to safe named (and numbered) entities
// as in makeSafeEntities(). Unlike mb_convert_encoding(), mb_encode_numericentity() will
// NOT skip any already existing entities in the string, so use a regex to skip them.
function makeAllEntities($str, $useNamedEntities = 0, $encoding = "") {
if (is_array($str)) {
foreach ($str as $s)
$arrOutput[] = makeAllEntities($s,$encoding);
return $arrOutput;
}
else if (!empty($str)) {
$str = makeUTF8($str,$encoding);
if ($useNamedEntities)
$str = mb_convert_encoding($str,"HTML-ENTITIES","UTF-8");
$str = makeTagEntities($str,$useNamedEntities);
// Fix backslashes so they don't screw up following mb_ereg_replace
// Single quotes are fixed by makeTagEntities() above
$str = mb_ereg_replace('\\\\',"&#92;", $str);
mb_regex_encoding("UTF-8");
$str = mb_ereg_replace("(?>(&(?:[a-z]{0,4}\w{2,3};¦#\d{2,5};)))¦(\S+?)",
"'\\1'.mb_encode_numericentity('\\2',array(0x0,0x2FFFF,0,0xFFFF),'UTF-8')", $str, "ime");
$str = correctIllegalEntities($str);
return $str;
}
}

// Convert common characters to named or numbered entities
function makeTagEntities($str, $useNamedEntities = 1) {
// Note that we should use &apos; for the single quote, but IE doesn't like it
$arrReplace = $useNamedEntities? array('&#39;','&quot;','&lt;','&gt;') : array('&#39;','&#34;','&#60;','&#62;');
return str_replace(array("'",'"','<','>'), $arrReplace, $str);
}

// Convert ampersands to named or numbered entities.
// Use regex to skip any that might be part of existing entities.
function makeAmpersandEntities($str, $useNamedEntities = 1) {
return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};¦#[0-9]{2,5};)/m", $useNamedEntities? "&amp;" : "&#38;", $str);
}

// Convert illegal HTML numbered entities in the range 128 - 159 to legal couterparts
function correctIllegalEntities($str) {
$chars = array(
128 => '&#8364;',
130 => '&#8218;',
131 => '&#402;',
132 => '&#8222;',
133 => '&#8230;',
134 => '&#8224;',
135 => '&#8225;',
136 => '&#710;',
137 => '&#8240;',
138 => '&#352;',
139 => '&#8249;',
140 => '&#338;',
142 => '&#381;',
145 => '&#8216;',
146 => '&#8217;',
147 => '&#8220;',
148 => '&#8221;',
149 => '&#8226;',
150 => '&#8211;',
151 => '&#8212;',
152 => '&#732;',
153 => '&#8482;',
154 => '&#353;',
155 => '&#8250;',
156 => '&#339;',
158 => '&#382;',
159 => '&#376;');
foreach (array_keys($chars) as $num)
$str = str_replace("&#".$num.";", $chars[$num], $str);
return $str;
}

// Compare to native utf8_encode function, which will re-encode text that is already UTF-8
function makeUTF8($str,$encoding = "") {
if (!empty($str)) {
if (empty($encoding) && isUTF8($str))
$encoding = "UTF-8";
if (empty($encoding))
$encoding = mb_detect_encoding($str,'UTF-8, ISO-8859-1');
if (empty($encoding))
$encoding = "ISO-8859-1"; // if charset can't be detected, default to ISO-8859-1
return $encoding == "UTF-8"? $str : @mb_convert_encoding($str,"UTF-8",$encoding);
}
}

// Much simpler UTF-8-ness checker using a regular expression created by the W3C:
// Returns true if $string is valid UTF-8 and false otherwise.
// From http://w3.org/International/questions/qa-forms-utf-8.html
function isUTF8($str) {
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] // ASCII
¦ [\xC2-\xDF][\x80-\xBF] // non-overlong 2-byte
¦ \xE0[\xA0-\xBF][\x80-\xBF] // excluding overlongs
¦ [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} // straight 3-byte
¦ \xED[\x80-\x9F][\x80-\xBF] // excluding surrogates
¦ \xF0[\x90-\xBF][\x80-\xBF]{2} // planes 1-3
¦ [\xF1-\xF3][\x80-\xBF]{3} // planes 4-15
¦ \xF4[\x80-\x8F][\x80-\xBF]{2} // plane 16
)*$%xs', $str);
}
?>

Then in the process