Thursday, May 27, 2010

Replacing $_POST with an object

Leave a Comment
Before I begin, please, allow me to introduce myself as a fan of the Object Oriented Programming (OOP). When PHP announced the release of the PHP5, I was keen on moving into PHP5 as soon as I realized all the benefits that it provides. It seems a bit awkward for a PHP developer also to be an OOP fan. Someone could easily tell me, "why bother with PHP and not programming with a full OOP language, such as Java or .NET Framework etc". The answer might be obvious , to people who knows me well. I just like PHP!

But let's cut to the chase, a few days ago I was checking some old projects, from the pre-MVC era, that were developed without the use of a sophisticated MVC Framework, such as Zend Framework, CakePHP, Codeigniter etc, which are providing a plethora of libraries that makes your life much easier. So, I had a revelation that I would like to share with you.

In such a project, I noticed that there was no checking for cross-site scripting attacks (XSS), making those sites vulnerable to malicious attackers. I had to figure out a solution without having to add a "check", using a proper function, every time a posted variable was retrieved.

i.e:

[php] <?php $some_value = xss_clean($_POST['some_variable']); ?>[/php]

So I came up with the idea altering the $_POST array with an object which every time a posted variable was retrieved, there will be a call to a method which it should make the XSS checking and it will return the value.

The trick can be done with the use of the ArrayObject (introduced in PHP5), which allows you to access an object as it was an array. So all I had to do, it was to create a class that will extends the ArrayObject and then overload the ArrayObject::offsetGet method to add the extra functionality that it was needing.

The class could be like this:

[php]
<?php
class PostClass extends ArrayObject{
//create the class constructor
function __construct(){
//initialize the parent class and set the $_POST array as the the input parameter
parent::__construct($_POST);
}
//Overloading the method
function offsetGet($index){
return $this->xss_check(parent::offsetGet($index));
}
//Add a private method for the XSS checking
private function xss_check($value){
//Write some code here to validate the data
return $value;
}
}
//Finally replacing the $_POST array with an instance of the PostClass class.
$_POST = new PostClass();
?>
[/php]

Save those lines of code into a file and include it in the first line of the page that you need to clear posted data.

i.e:

[php]<?php include 'anAwesomeTrick.php' ?>[/php]

And vuala! When you are trying to retrieve some posted data with the usual way,

i.e:

[php]<?php $some_data = $_POST['some_data']; ?>[/php]

there will be a call at the PostArray::offsetGet method that makes the XSS checking and returns the value clean from possible malicious scripts.

You have the same functionally as before, with the risk of being XSS attacked eliminated.

Cheers ;)

Σύντομη περίληψη στα Ελληνικά:
Μέθοδος αντικατάστασης του $_POST πίνακα με ένα αντικείμενο που να κάνει χρήση της κλάσης ArrayObject, έτσι ώστε να υπάρχει δυνατότητα επέμβασης στα δεδομένα του πίνακα κατά την ανάκτησή τους. Σε αυτό το άρθρο προτείνω τον καθαρισμό των δεδομένων από επιθέσεις XSS, σε συστήματα χωρίς αυτήν τη δυνατότητα, γράφοντας όσο το δυνατό λιγότερο νέο κώδικα και προπάντων χωρίς να χρειαστεί να αλλάξετε τίποτα στον ήδη υπάρχοντα.