FIEO with PHP 5 Interceptors

Note: Before getting into this, it may be easier to just download the file, run the code, then read this post.

Thanks to the efforts of Chris Shiflett and other PHP security experts, Filter Input/Escape Output (FIEO) is now a commonplace technique to increase web application security.

The idea itself is simple. When data comes into your application, it must be filtered prior to it actually being used for any reason. This means all data. Form values, URL values, and yes, even the values in the forever useful $_SERVER superglobal. If you expect an integer, cast it as such. Maybe you are expecting plain text, anything that looks like HTML should obviously be removed. Whitelists also apply here, too.

Before leaving your application, data should be properly escaped with the specific output medium in mind. For example, if you are passing it off to a MySQL database, make sure quotes (or any other tricky character) is prefixed with a slash. Another example would be if you are rendering data out to a web page, htmlentities() (or something similar) should be used to transform html-specific characters into their proper entities.

In my last post I showed how PHP 5’s interceptor methods can be used to build collections of data. That same technique can be applied to FIEO. This is what it looks like implemented:

<?php $sampleData = array(     ‘title’ => ‘Someone & Someone Else’,     ‘content’ => ‘Someone said to someone else, "Hello, World!"’ ); $sampleContexts = array(     ‘html’ => ‘MikeG_HtmlFilter’,     ’sql’ => ‘MikeG_SqlFilter’ ); $Filter = new Panda_DataFilter($sampleData, $sampleContexts); $Filter->html->setCharset(‘ISO-8859-1′); ?> <h1><?php echo $Filter->html->title ?></h1> <p><?php echo $Filter->html->content ?></p> <p><?php echo $Filter->sql->content ?></p>

And the output is:

<h1>Someone &amp; Someone Else</h1> <p>Someone said to someone else, &quot;Hello, World!&quot;</p> <p>Someone said to someone else, \\"Hello, World!\\"</p>

Pretty neat huh? I think so too.

The idea is simple: Instances of Panda_DataFilter contains the tainted data. You load contexts into Panda_DataFilter and they govern the input and output of the tainted data. In the example above, I output data using the html and sql contexts. Whenever you set a variable inside of one of the loaded contexts, __set will intercept the assignment operation and run it’s specific input filtering routine. Likewise, whenver you read a value from one of the contexts, __get intercepts the retrieval operation and runs its specific output escaping routine.

Here’s the actual code:

<?php final class Panda_DataFilter {     protected $data = array();         public function __construct(array $data, array $contexts)     {         $this->data = $data;         foreach ($contexts as $contextName => $context) {             $this->{$contextName} = new $context($this->data);         }     } } abstract class Panda_DataFilter_Context {     protected $data = array();     public function __construct(array $data)     {         foreach ($data as $key => $value) {             $this->{$key} = $value;         }     }     abstract public function __get($name);     abstract public function __set($name, $value); } ?>

And the html and sql contexts:

<?php class MikeG_HtmlFilter extends Panda_DataFilter_Context {     private $charset = ‘UTF-8′;     private $quotes = ENT_COMPAT;     public function __get($name)     {         return htmlentities($this->data[$name], $this->quotes, $this->charset);     }     public function __set($name, $value)     {         $this->data[$name] = $value;     }     public function setCharset($charset)     {         $this->charset = $charset;     }     public function setQuoteStyle($quoteStyle)     {         $this->quotes = $quoteStyle;     } } class MikeG_SqlFilter extends Panda_DataFilter_Context {     public function __get($name)     {         return mysql_escape_string($this->data[$name]);     }         public function __set($name, $value)     {         $this->data[$name] = $value;     } } ?>

Hopefully someone finds this useful :)

This entry was posted on Tuesday, October 30th, 2007 at 8:16 pm and is filed under Code, Design Patterns, PHP. You can leave a response, or trackback from your own site.

7 Responses to FIEO with PHP 5 Interceptors

PHPDeveloper.org:

On November 8th, 2007 at 8:27 am #

Michael Girouard’s Blog: FIEO with PHP 5 Interceptors…

Michael Girouard has a post on his blog about something that’s ……

developercast.com » Michael Girouard’s Blog: FIEO with PHP 5 Interceptors:

On November 8th, 2007 at 10:37 am #

[…] Girouard has a post on his blog about something that’s becoming more and more wide-spread in the PHP community (thankfully) - […]

daaku:

On November 8th, 2007 at 12:06 pm #

Current versions of PHP (>5.2.0) have the filter extension: http://php.net/filter - it only deals with input, and htmlentities can be used for output.

Pro::PHP Newscast (Nov 8, 2007) | PHP Podcasts:

On November 11th, 2007 at 11:27 am #

[…] FEIO with Interceptors […]

Michael Girouard’s Blog: FIEO with PHP 5 Interceptors | MT-Soft Website Development:

On November 13th, 2007 at 12:34 pm #

[…] Posted in November 13th, 2007 by admin in PHP, Programming, Security Michael Girouard has a post on his blog about something that’s becoming more and more wide-spread in the PHP community (thankfully) - […]

Rolling Your Own MVC: The Page Load Scenario :: Love Mike G.:

On April 9th, 2008 at 9:04 pm #

[…] it may not seem like it makes sense to duplicate it here; however, it affords us the ability to filter the data as it comes in and as it goes […]

James Morris:

On April 11th, 2008 at 6:18 am #

This is a nice little method of filtering - I will be refering to it most likely in the future, cheers for the post.

What do you have to say?

Site Stuff

Pages

Projects

Archives

Categories