Small, short code snippets that other people may find useful. Do you have a good regex that you would like to share? Share it! Even better, the code can be commented on, and improved.
I'm sure most everyone here is aware of the dangers of using raw GET/POST data, and of the importance of data validation, etc... But I wrote a class to help aid in making sure you don't accidentally use data without having checked it.
The "documentation" explains some of the finer details. Check here for any updated versions before you gank this code, as I may not always remember to come back here and edit updates in.
And by all means, if you have any comments/criticisms please share them.
<?php
/**
* Title: FormTaint
*
* Author: Robert Paul
*
* Version: 1.0 Alpha
*
* Date: 27 Nov, 2005
*
* Purpose: The purpose of this class is to provide 'secure' access to values sent from client-side
* sources. Upon construction, values are loaded into the class via a superglobal ($_POST or $_GET).
* Since they are client-side values, they are considered tainted and must be validated by a
* validation scheme.
*
* Taintedness is boolean: there are no levels of data "safeness" here like there are
* in Ruby's taint model.
*
* Since FormTaint in an abstract class it MUST be extended by a child class with a
* validateValue() method. While it could be possible to include "default" validation there is
* little benefit to this The upswing is that one can make reusable form validation template sets
* (i.e. BlogPost or Login, etc...) that can be further extended for site-specific purposes.
*
* FormTaint requires PHP 5.0 or higher, however could be easily modified so as to be
* PHP4 compatible. Probably just by removing abstract/private/public declarations and renaming
* __construct to FormTaint.
*
* License: GPL 2.0 - http://www.gnu.org/copyleft/gpl.html#SEC1
**/
abstract class FormTaint {
private $valueArray = array();
/**
* Constructor: Imports values into class's structure.
**/
private function __construct($type) {
if($type != "POST" && $type != "GET") {
trigger_error("Improper constructor argument. 'GET' or 'POST' expected.", E_USER_ERROR);
}
$type .= "_$type";
foreach($$type as $key => $value) {
$this->valueArray[$key] = array();
$this->valueArray[$key]['value'] = $value;
$this->valueArray[$key]['tainted'] = TRUE;
}
}
/**
* validateValue must be a method defined by the child class. This allows you to extend
* FormTaint on a per-form basis and have custom validation sets. One possible implementation
* is shown below the method declaration.
**/
abstract public function validateValue($valueName, $method);
/**
* abstract public function validateValue($valueName, $method) {
* //check for regex delimiter
* if(strpos($method, '/') == 0)
* if (preg_match($method, $this->arrayValues[$valueName]['value']))
* $this->untaintValue($valueName);
*
* return $this->isTainted($valueName);
* }
**/
/**
* Attempting to use tainted data triggers an E_USER_NOTICE. THIS DOES NOT STOP THE EXECUTION
* OF THE SCRIPT. Change to E_USER_ERROR if you want to halt the script upon tainted data
* access. It'd certainly make for some "kick in the pants" debugging...
**/
public function getValue($valueName) {
if ($this->isTainted($valueName))
trigger_error("$valueName is tainted. Validate it before using!", E_USER_NOTICE);
return $this->valueArray[$valueName]['value'];
}
/**
* Note that the taint status is reset to TRUE when a new value is set. This is to ensure that
* you don't accidentally put tainted data in.
**/
public function setValue($valueName, $newValue) {
$this->valueArray[$valueName]['value'] = $newValue;
$this->taintvalue($valueName);
}
/**
* Returns $valueName's taint status.
**/
private function isTainted($valueName) {
return $this->valueArray[$valueName]['tainted'];
}
/**
* Sets $valueName as untainted.
**/
private function untaintValue($valueName) {
$this->valueArray[$valueName]['tainted'] = FALSE;
}
/**
* Sets $valueName as tainted.
**/
private function taintValue($valueName) {
$this->valueArray[$valueName]['tainted'] = TRUE;
}
}
?>
RobertPaul wrote:It is indeed. I don't know who uses what version around here but I get the feeling it'd be smart of me to put together a PHP4 version.
<?php
/**
* Title: FormTaint
*
* Author: Robert Paul
*
* Version: 1.0 Alpha
*
* Date: 27 Nov, 2005
*
* Purpose: The purpose of this class is to provide 'secure' access to values sent from client-side
* sources. Upon construction, values are loaded into the class via a superglobal ($_POST or $_GET).
* Since they are client-side values, they are considered tainted and must be validated by a
* validation scheme.
*
* Taintedness is boolean: there are no levels of data "safeness" here like there are
* in Ruby's taint model.
*
* Since FormTaint in an abstract class it MUST be extended by a child class with a
* validateValues() method. While it could be possible to include "default" validation there is
* little benefit to this The upswing is that one can make reusable form validation template sets
* (i.e. BlogPost or Login, etc...) that can be further extended for site-specific purposes.
*
*
* License: GPL 2.0 - http://www.gnu.org/copyleft/gpl.html#SEC1
**/
class FormTaint {
var $valueArray = array();
/**
* Constructor: Imports values into class's structure.
**/
function FormTaint($type) {
if($type != "POST" && $type != "GET") {
trigger_error("Improper constructor argument. 'GET' or 'POST' expected.", E_USER_ERROR);
}
$type .= "_$type";
foreach($$type as $key => $value) {
$this->valueArray[$key] = array();
$this->valueArray[$key]['value'] = $value;
$this->valueArray[$key]['tainted'] = TRUE;
}
}
/**
* validateValue must be a method defined by the child class. This allows you to extend
* FormTaint on a per-form basis and have custom validation sets. One possible implementation
* is shown below the method declaration.
**/
function validateValue($valueName, $method) {
}
/**
* function validateValue($valueName, $method) {
* //check for regex delimiter
* if(strpos($method, '/') == 0)
* if (preg_match($method, $this->arrayValues[$valueName]['value']))
* $this->untaintValue($valueName);
*
* return $this->isTainted($valueName);
* }
**/
/**
* Attempting to use tainted data triggers an E_USER_NOTICE. THIS DOES NOT STOP THE EXECUTION
* OF THE SCRIPT. Change to E_USER_ERROR if you want to halt the script upon tainted data
* access. It'd certainly make for some "kick in the pants" debugging...
**/
function getValue($valueName) {
if ($this->isTainted($valueName))
trigger_error("$valueName is tainted. Validate it before using!", E_USER_NOTICE);
return $this->valueArray[$valueName]['value'];
}
/**
* Note that the taint status is reset to TRUE when a new value is set. This is to ensure that
* you don't accidentally put tainted data in.
**/
function setValue($valueName, $newValue) {
$this->valueArray[$valueName]['value'] = $newValue;
$this->taintValue($valueName);
}
/**
* Returns $valueName's taint status.
**/
function isTainted($valueName) {
return $this->valueArray[$valueName]['tainted'];
}
/**
* Sets $valueName as untainted.
**/
function untaintValue($valueName) {
$this->valueArray[$valueName]['tainted'] = FALSE;
}
/**
* Sets $valueName as tainted.
**/
function taintValue($valueName) {
$this->valueArray[$valueName]['tainted'] = TRUE;
}
}
?>
Last edited by RobertPaul on Mon Nov 28, 2005 6:45 am, edited 1 time in total.
I'm not sure I'd like messages to be sent informing the user that input is tainted :s
I know that in an ideal world we all have error_reporting(0); and display_errors off on our production environments, but none the less the chance is still there.
I would also prefer them to be warnings, they are after all potentially critical security issues!