Form Data Taint Model

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.

Moderator: General Moderators

Post Reply
RobertPaul
Forum Contributor
Posts: 122
Joined: Sun Sep 18, 2005 8:54 pm
Location: OCNY

Form Data Taint Model

Post by RobertPaul »

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.

Code: Select all

<?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;
    }
}
?>
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Note: this is php5+ only
RobertPaul
Forum Contributor
Posts: 122
Joined: Sun Sep 18, 2005 8:54 pm
Location: OCNY

Post by RobertPaul »

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. :wink:
User avatar
n00b Saibot
DevNet Resident
Posts: 1452
Joined: Fri Dec 24, 2004 2:59 am
Location: Lucknow, UP, India
Contact:

Post by n00b Saibot »

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. :wink:
indeed a vast majority is PHP4 :wink:
RobertPaul
Forum Contributor
Posts: 122
Joined: Sun Sep 18, 2005 8:54 pm
Location: OCNY

Post by RobertPaul »

And there you have it.

Code: Select all

<?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.
User avatar
n00b Saibot
DevNet Resident
Posts: 1452
Joined: Fri Dec 24, 2004 2:59 am
Location: Lucknow, UP, India
Contact:

Post by n00b Saibot »

errrrmmm... does PHP4 has __construct() 8O
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

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!

my $0.02 :)
RobertPaul
Forum Contributor
Posts: 122
Joined: Sun Sep 18, 2005 8:54 pm
Location: OCNY

Post by RobertPaul »

n00b Saibot wrote:errrrmmm... does PHP4 has __construct() 8O
It's too early. :oops:

Jenk wrote:I would also prefer them to be warnings, they are after all potentially critical security issues!
Cool, I'll check that out. I wasn't really sure which one to use.
Post Reply