Secure Programming With The Zend Framework
Secure Programming With The Zend Framework
de
Stefan Esser
• from Cologne / Germany
• Authentication
• Input Validation and Input Filtering
• SQL Security
• Cross Site Request Forgery (CSRF) Protection
• Session Management Security
• Cross Site Scripting (XSS) Protection
<?php
$email = $this->getRequest()->getPost('email', 'none@example.com');
<?php
// Creating a Validator Chain
$validatorChain = new Zend_Validate();
$validatorChain->addValidator(new Zend_Validate_StringLength(6, 12))
->addValidator(new Zend_Validate_Alnum());
// Validation of "username"
if ($validatorChain->isValid($username)) {
// "username" is valid
} else {
// "username" is invalid; Outputting the reasons
foreach ($validatorChain->getMessages() as $message) {
echo "$message\n";
}
}
?>
<?php
$message = $this->getRequest()->getPost('message', '');
<?php
// Create a filter chain and add filters
$filterChain = new Zend_Filter();
$filterChain->addFilter(new Zend_Filter_Alpha())
->addFilter(new Zend_Filter_StringToLower());
// Filtering "username"
$username = $filterKette->filter($username);
?>
// stop processing
return $this->render('form');
}
$validators = array(
'month' => array(
new Zend_Validate_Int(),
new Zend_Validate_Between(1, 12)
)
);
$params = $this->getRequest()->getParams();
$input = new Zend_Filter_Input($filters, $validators, $params);
if ($input->isValid()) {
echo "OK\n";
}
<?php
$sql = "SELECT id FROM _users WHERE lastname=? AND age=?";
$params = array('Smith', '18');
$res = $db->fetchAll($sql, $params);
?>
$minimumPrice = 100;
$maximumPrice = 500;
$prod = 'Apple';
$select = $db->select()
->from('products',
array('product_id', 'product_name', 'price'))
->where("price < $minimumPrice OR price > $maximumPrice")
->where('product_name = ?', $prod);
$form->addElement('hash', 'csrf_token',
array('salt' => 's3cr3ts4ltG%Ek@on9!'));
<?php
class My_Form extends Zend_Form
{
function __construct()
{
parent::__construct();
$this->addElement('hash', 'csrf_token',
array('salt' => get_class($this) . 's3cr3t%Ek@on9!'));
}
}
?>
/**
• Token algorithm could be * Generate CSRF token
*
improved */
protected function _generateHash()
• avoid mt_rand() {
$this->_hash = md5(
mt_rand(1,1000000)
• more entropy . $this->getSalt()
. $this->getName()
. mt_rand(1,1000000)
• but it is safe enough );
(for now) $this->setValue($this->_hash);
}
• Session Fixation
• is harder in case of session validation / strict session handling
• but is only stopped by regenerating the session id after each
change in status
Zend_Session::regenerateId();
<?php
try {
Zend_Session::start();
} catch (Zend_Session_Exception $e) {
Zend_Session::destroy();
Zend_Session::start();
Zend_Session::regenerateId();
}
Zend_Session::registerValidator(new Zend_Session_Validator_HttpUserAgent());
?>
/**
* Setup() - this method will get the client's remote address and store
* it in the session as 'valid data'
*
* @return void
*/
public function setup()
{
$this->setValidData( (isset($_SERVER['REMOTE_ADDR'])
? $_SERVER['REMOTE_ADDR'] : null) );
}
/**
* Validate() - this method will determine if the client's remote addr
* matches the remote address we stored when we initialized this variable.
*
* @return bool
*/
public function validate()
{
$currentBrowser = (isset($_SERVER['REMOTE_ADDR'])
? $_SERVER['REMOTE_ADDR'] : null);
}
?>
• preventing XSS is error prone - one XSS for every forgotten encoding
• automatically scanning for forgotten escaping is hard
• directly echoing variables should be forbidden (e.g. with Bytekit + pre-commit-hook)
• output only via Zend_View_Helper
• preventing XSS becomes job of Zend_View_Helper
Questions ?
http://www.sektioneins.de