php basic security
TRANSCRIPT
Basic security.
• learn how to validate user input and deal with potentially unsafe data.
• when designing an application, developer had to include an input validation routine.
• a failure to do this can result into serious problems, or even cause the application to break when it encounters invalid or corrupt data.
• Tips to validate user input, and provide user notification in understandable and non-threatening way (user friendly)
Introduction
The Common Input Errors1. Empty record -assuming no NOT NULL
constraints on the target table• Solution:• To avoid this, it's important to verify that the
form does, in fact, contain valid data, and only then perform the INSERT query
• the trim() function - used to trim leading and trailing spaces from the field value, then compared with an empty string. If the match is true, the field was submitted empty, and the script dies with an error message before MySQL comes into the picture.
• Example :security2.php
security2.php<html>
<head></head><body><?phpif (!isset($_POST['submit'])) {?> <form action = '<?php $_SERVER['PHP_SELF'] ?>' method = 'post'> Which sandwich filling would you like? <br /> <input type = 'text' name = 'filling'> <br /> <input type = 'submit' name = 'submit' value = 'Save'> </form><?php}else { // check for required data // die if absent if (!isset($_POST['filling']) || trim($_POST['filling']) == '') { die("ERROR: You can't have a sandwich without a filling!"); } else { $filling = mysql_escape_string(trim($_POST['filling'])); }
// set database variables $host = 'localhost'; $user = 'user'; $pass = 'secret'; $db = 'sandwiches';
// open connection $connection = mysql_connect($host, $user, $pass) or die('Unable to connect!');
// select database mysql_select_db($db) or die('Unable to select database!');
// create query $query = 'INSERT INTO orders (filling) VALUES ("$filling")';
// execute query $result = mysql_query($query) or die("Error in query: $query. ".mysql_error());
// close connection mysql_close($connection);
// display message echo "Your {$_POST['filling']} sandwich is coming right up!";}?></body></html>
2. Wrong Data type or size- is_numeric() function-checked if the value is numeric. It tests a string to see if it is a numeric.
- intval() function -to test if it's an integerExample :datatype4.php
datatype4.php<html><head></head><body><?phpif (!isset($_POST['submit'])) {?> <form action = '<?php $_SERVER['PHP_SELF']?>' method = 'post'> How many sandwiches would you like? (min 1, max 9) <br /> <input type = 'text' name = 'quantity'> <br /> <input type = 'submit' name = 'submit' value = 'Save'> </form><?php}else { // check for required data // die if absent if (!isset($_POST['quantity']) || trim($_POST['quantity']) == '') { die ("ERROR: Can't make 'em if you don't say how many!"); }
// check if input is a number if (!is_numeric($_POST['quantity'])) { die ("ERROR: Whatever you just said isn't a number!"); }
// check if input is an integer if (intval($_POST['quantity']) != $_POST['quantity']) { die ("ERROR: Can't do halves, quarters or thirds... I'd lose my job!"); }
// check if input is in the range 1-9 if (($_POST['quantity'] < 1) || ($_POST['quantity'] > 9)) { die ('ERROR: I can only make between 1 and 9 sandwiches per order!'); }
// process the data echo "I'm making you {$_POST['quantity']} sandwiches. Hope you can eat them all!";}?></body></html>
-the strlen() function- returns the length of a string.
Example :strlen5.php
<html><head></head><body><?phpif (!isset($_POST['submit'])) {?> <form action = '<?php $_SERVER['PHP_SELF']?>' method = 'post'> Enter a nickname 6-10 characters long: <br /> <input type = 'text' name = 'nick'> <br /> <input type = 'submit' name = 'submit' value = 'Save'> </form><?php}else {
// check for required data
// die if absent if (!isset($_POST['nick']) || trim($_POST['nick']) == '') { die ('ERROR: Come on, surely you can think of a nickname! How about Pooky?'); }
// check if input is of the right length if (!(strlen($_POST['nick']) >= 6 && strlen($_POST['nick']) <= 10)) { die ("ERROR: That's either too long or too short!"); }
// process the data echo "I'll accept the nickname {$_POST['nick']}, seeing as it's you!";}?></body></html>
3. Date validation-important to check that date values provided by the user are valid before using them in a calculation.Eg:29-Feb-2005 or 31-Apr-2005 -the checkdate() function- accepts three arguments - month, day and year - and returns a Boolean value indicating whether or not the date is valid. Example:date6.php
date6.php
<html><head></head><body><?phpif (!isset($_POST['submit'])) {?> <form action = '<?php $_SERVER['PHP_SELF']?>' method = 'post'> Enter your date of birth: <br /><br /> <select name = 'day'> <?php // generate day numbers for ($x = 1; $x <= 31; $x++) { echo "<option value = $x>$x</option>"; } ?> </select> <select name = 'month'> <?php // generate month names for ($x = 1; $x <= 12; $x++) { echo "<option value=$x>".date('F', mktime(0, 0, 0, $x, 1, 1)).'</option>'; }
?> </select> <select name = 'year'> <?php
// generate year values for ($x = 1950; $x <= 2005; $x++) { echo "<option value=$x>$x</option>"; } ?> </select> <br /><br /> <input type = 'submit' name = 'submit' value = 'Save'> </form><?php}else { // check if date is valid if (!checkdate($_POST['month'], $_POST['day'], $_POST['year'])) { die("ERROR: The date {$_POST['day']}-{$_POST['month']}-{$_POST['year']} doesn't exist!"); }
// process the data echo "You entered {$_POST['day']}-{$_POST['month']}-{$_POST['year']} - which is a valid date.";}?></body></html>
4. multiple-choice form elements -eg: drop-down list boxes and radio buttons-in cases where it's mandatory to make a choice -to validate: when the form is submitted, selections made are placed in an array, is_array() and sizeof() functions are used to ensure that it contains at least one element. Example:multichoice7.php
multichoice7.php
<html><head></head><body><?phpif (!isset($_POST['submit'])) {?> <form action = '<?php $_SERVER['PHP_SELF'] ?>' method = 'post'> Pizza base: <br /> <input type = 'radio' name = 'base' value = 'thin and crispy'>Thin and crispy <input type = 'radio' name = 'base' value = 'deep-dish'>Deep-dish <br />Cheese: <br /> <select name = 'cheese'> <option value = 'mozzarella'>Mozzarella</option> <option value = 'parmesan'>Parmesan</option> <option value = 'gruyere'>Gruyere</option> </select> <br /> Toppings: <br /> <select multiple name = 'toppings[]'> <option value = 'tomatoes'>Tomatoes</option> <option value = 'olives'>Olives</option> <option value = 'pepperoni'>Pepperoni</option> <option value = 'onions'>Onions</option>
<option value = 'peppers'>Peppers</option> <option value = 'sausage'>Sausage</option> <option value = 'anchovies'>Anchovies</option> </select> <br /> <input type = 'submit' name = 'submit' value = 'Save'> </form><?php}else { // check radio button if (!isset($_POST['base'])) { die('You must select a base for the pizza'); }
// check list box if (!isset($_POST['cheese'])) { die('You must select a cheese for the pizza'); }
// check multi-select box if (!is_array($_POST['toppings']) || sizeof($_POST['toppings']) < 1) { die('You must select at least one topping for the pizza'); }
// process the data echo "One {$_POST['base']} {$_POST['cheese']} pizza with "; foreach ($_POST['toppings'] as $topping) echo $topping.", "; echo "coming up!";}?></body></html>
5. regular expressions
-used for pattern matching and substitution
-regular expression matching takes place with the ereg() or preg_match() functions and eregi() for a case-insensitive version
-Example: security9.php,using the email address validator
security9.php
<html><head></head><body><?phpif (!isset($_POST['submit'])) {?> <form action = '<?php $_SERVER['PHP_SELF'] ?>' method = 'post'> Email address: <br /> <input type = 'text' name = 'email'> <input type = 'submit' name = 'submit' value = 'Save'> </form><?php}else { // check email address if (!ereg('^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-]+)*\.([a-zA-Z]{2,6})$', $_POST['email'])) { die("Dunno what that is, but it sure isn't an email address!"); }
// process the data echo "The email address {$_POST['email']} has a valid structure. Doesn't mean it works!";}?></body></html>
Sample application
• PHP class that exposes basic object methods for data validation and error handling, and then use it to validate a form.
• Example:classformValidator.php
• consists of 2 components:
a) methods that accept the data to be validated, test the data to see whether it is valid or not
classformValidator.php
<?php// PHP 5
// class definition// class encapsulating data validation functionsclass formValidator {
// define properties private $_errorList;
// define methods // constructor public function __construct() { $this->resetErrorList(); }
// initialize error list private function resetErrorList() { $this->_errorList = array(); }
// check whether input is empty public function isEmpty($value) { return (!isset($value) || trim($value) == '') ? true : false; }
// check whether input is a string public function isString($value) { return is_string($value); }
// check whether input is a number public function isNumber($value) { return is_numeric($value); }
// check whether input is an integer public function isInteger($value) { return (intval($value) == $value) ? true : false; }
• isEmpty() - tests if a value is an empty string • isString() - tests if a value is a string • isNumber() - tests if a value is a numeric string • isInteger() - tests if a value is an integer • isAlpha() - tests if a value consists only of
alphabetic characters • isEmailAddress() - tests if a value is an email
address • isWithinRange() - tests if a value falls within a
numeric range • isInArray() - tests if a value exists in an array
// check whether input is alphabetic public function isAlpha($value) { return preg_match('/^[a-zA-Z]+$/', $value); }
// check whether input is within a numeric range public function isWithinRange($value, $min, $max) { return (is_numeric($value) && $value >= $min && $value <= $max) ? true : false; } // check whether input is a valid email address public function isEmailAddress($value) { return eregi('^([a-z0-9])+([\.a-z0-9_-])*@([a-z0-9_-])+(\.[a-z0-9_-]+)*\.([a-z]{2,6})$', $value); }
// check if a value exists in an array public function isInArray($array, $value) { return in_array($value, $array); }
b) a PHP array that holds a list of all the errors encountered during the validation process
• isError() - check if any errors exist in the error list
• addError() - add an error to the error list • getErrorList() - retrieve the current list of errors • resetErrorList() - reset the error list
// add an error to the error list public function addError($field, $message) { $this->_errorList[] = array('field' => $field, 'message' => $message); }
// check if errors exist in the error list public function isError() { return (sizeof($this->_errorList) > 0) ? true : false; }
// return the error list to the caller public function getErrorList() { return $this->_errorList; }
// destructor // de-initialize error list public function __destruct() { unset($this->_errorList); }
// end class definition}
?>
• To process the class, processor.php is needed:• Functions used are listed below:• isEmpty() method -used to test if required fields
have been filled in• isEmailAddress() and isWithinRange() methods-
used for more precise validation.• isInArray() method- check boxes and multiple-select
lists• a foreach() loop iterates over the list of errors and
prints them in a bulleted list.
processor.php
<?php
// include file containing classinclude('class.formValidator.php');
// instantiate object$fv = new formValidator();
// start checking the data
// check nameif ($fv->isEmpty($_POST['name'])) { $fv->addError('Name', 'Please enter your name');}
// check age and age rangeif (!$fv->isNumber($_POST['age'])) { $fv->addError('Age', 'Please enter your age');}else if (!$fv->isWithinRange($_POST['age'], 1, 99)) { $fv->addError('Age', 'Please enter an age value in the numeric range 1-99');}
// check sexif (!isset($_POST['sex'])) { $fv->addError('Sex', 'Please select your gender');}
// check email addressif (!$fv->isEmailAddress($_POST['email'])) { $fv->addError('Email address', 'Please enter a valid email address');}
// check colorif ($fv->isEmpty($_POST['color'])) { $fv->addError('Color', 'Please select one of the listed colors');}
// check insurance typeif ($fv->isEmpty($_POST['insurance'])) { $fv->addError('Insurance', 'Please select one of the listed insurance types');}
// check optional featuresif (isset($_POST['options'])) { if ($fv->isInArray($_POST['options'], '4WD') && !$fv->isInArray($_POST['options'], 'PSTR')) { $fv->addError('Optional features', 'Please also select Power Steering if you would like Four-Wheel Drive'); }}
// check to see if any errors were generatedif ($fv->isError()) { // print errors echo '<b>The operation could not be performed because one or more error(s) occurred.</b> <p /> Please resubmit the form after making the following changes:'; echo '<ul>'; foreach ($fv->getErrorList() as $e) { echo '<li>'.$e['field'].': '.$e['message']; } echo '</ul>';}else { // do something useful with the data echo 'Data OK';}
?>