Thursday, October 06, 2011

PHP security tips

When programming in PHP please pay attention to the following tips. PHP code examples below try to make it impossible to make a mistake by hiding default (non-secure) variables and securing the data on the fly. When you get used to it, you will be able to smell insecure code.

Validating input

Don’t use values from $_REQUEST ($_GET, $_POST) directly assuming they contain data of the necessary data type. Validation or casting is required. For example intval($_REQUEST['id']) will make sure you have an integer. Using a dedicated class for reading URL/Form parameters will allow you to unset($_REQUEST) completely making sure you (or any other developer) is using casting or validation. For example:

class Request {
protected $data = array();

function __construct($other = NULL) {
     $this->data = $other ?: $_REQUEST;
     if (!$other) unset($_REQUEST);
}

function getInt($name) {
     return intval($this->data[$name]);
}

function getTrim($name) {
return trim($this->data[$name]);
}
}

$r = new Request();
echo $r->getInt('id');  // 15
echo $_REQUEST['id'];   // NULL

Note that once you created an instance of the Request class you can't use $_REQUEST anymore, which is good. Request could be made a singleton in order to be able to access it from multiple controllers.

Escape output

In order to prevent XSS you need to use htmlspecialchars() on every dynamic value which may come from the database, user input or web-service. Similarly to the example above it is recommended to close the possibility of using the values without escaping. For example the following View class (from MVC) doesn't allow accessing query results directly:


class View {
   protected $file;
   protected $caller;

   function __construct($file, $controller) {
        $this->file = $file;
        $this->caller = $controller;
   }

   function render() {
        $file = 'template/'.$this->file;
        ob_start();
        require($file);
        $content = ob_get_clean();
        return $content;
}

function __call($func, array $args) {
     $method = array($this->caller, $func);
     return call_user_func_array($method, $args);
}

function __get($var) {
     return htmlspecialchars($this->caller->$var);
}

}

$c = new Controller();
$c->dataXSS = '';
echo new View('output.phtml', $c);

// ---- output.phtml

Test View Controller


Must be escaped: dataXSS ?>


Note that in the template we can access data from the controller directly like this: dataXSS ?>, but this data will be processed with htmlspecialchars() invisibly for you.