Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
100% found this document useful (2 votes)
5K views

Secure Programming With The Zend Framework

The document discusses secure programming techniques when using the Zend Framework. It covers topics like authentication, input validation and filtering, SQL security, CSRF protection, session management security, and XSS protection. It explains how to implement authentication in controllers using the init() method. It also describes how to access and validate request parameters using the request object, validators, filters, and filter chains provided by the Zend Framework. Form validation and the Zend_Filter_Input class are also covered.

Uploaded by

kaplumb_aga
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (2 votes)
5K views

Secure Programming With The Zend Framework

The document discusses secure programming techniques when using the Zend Framework. It covers topics like authentication, input validation and filtering, SQL security, CSRF protection, session management security, and XSS protection. It explains how to implement authentication in controllers using the init() method. It also describes how to access and validate request parameters using the request object, validators, filters, and filter chains provided by the Zend Framework. Form validation and the Zend_Filter_Input class are also covered.

Uploaded by

kaplumb_aga
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 44

http://www.sektioneins.

de

Secure Programming with the


Zend-Framework
Stefan Esser <stefan.esser@sektioneins.de>

June 2009 - Amsterdam


Who I am?

Stefan Esser
• from Cologne / Germany

• Information-Security since 1998

• PHP Core Developer since 2001

• Month of PHP Bugs and Suhosin

• Head of Research and Development at SektionEins GmbH

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  2


Part I
Introduction

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  3


Introduction

• Using the Zend-Framework got very popular in the last years


• Growing request of security for Zend-Framework based applications
• Books/Talks/Seminars concentrate on secure programming of PHP
applications without a framework

• Using a framework requires different ways to implement protections


• Some frameworks come with their own security features

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  4


Topics

• Authentication
• Input Validation and Input Filtering
• SQL Security
• Cross Site Request Forgery (CSRF) Protection
• Session Management Security
• Cross Site Scripting (XSS) Protection

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  5


Part II
Authentication

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  6


Classic Applications vs. Zend-Framework

• Zend-Framework applications usually use a


MVC design with dispatcher Dispatcher

• Classic applications usually use neither a


MVC design, nor a dispatcher

• without dispatcher every reachable script Controller


must implement or embed authentication

• classic approach is error-prone


• often scripts exists that forget to
implement the authentication View Model

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  7


Central Authentication in Controller

• Deriving the Zend_Controller_Action


• Authentication implemented in init() method
• Attention: if a controller has an own init() method then method
of the parent class must be called
class My_Controller_Action extends Zend_Controller_Action
{
/**
* Init function
*
* First check if this is a logged in user, ...
*/
public function init()
{
$isLoggedIn = true;
try {
My_Auth::isLoggedIn();
} catch (My_Auth_UserNotLoggedInException $e) {
$isLoggedIn = false;
}
...
}

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  8


Part III
Input Validation and Input Filtering

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  9


Accessing Request Parameters (I)

• Traditionally PHP applications access user input directly


➡ $_GET, $_POST, $_COOKIE, $_REQUEST, $_SERVER, $_ENV, $_FILES

• Form of access also possible in Zend-Framework, but not usual


➡ Input validation and input filtering not directly portable from
traditional PHP applications

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  10


Accessing Request Parameters (II)

• Access via request object Zend_Controller_Request_Http


• Either via methods or magic properties
• Access is unfiltered - only raw data
• Access via magic property in the following order
1. internal parameter array
2. $_GET
3. $_POST
$message = $this->getRequest()->message;
4. $_COOKIE
5. $_SERVER
6. $_ENV

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  11


Accessing Request Parameters (III)

• function getQuery($key = null, $default = null)


• function getPost($key = null, $default = null)
• function getCookie($key = null, $default = null)
• function getServer($key = null, $default = null)
• function getEnv($key = null, $default = null)
• wrapper around $_GET / $_POST / $_COOKIE / $_SERVER / $_ENV with the
possibility to return a default value

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  12


Accessing Request Parameters (IV)

• function getParam($key = null, $default = null)


• gets parameters from the internal parameter array and from $_GET and
$_POST or returns the default value

• parameter sources can be configured ($_GET / $_POST)


• similar to $_REQUEST without $_COOKIE

• function getParams($key = null, $default = null)


• gets all parameters from the internal parameter array, $_GET and $_POST
• in case of double entries, later entries will overwrite the earlier entries

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  13


Validation with Zend_Validate

• Validators to validate parameters


• Zend-Framework comes with a set of validators
Alnum, Alpha, Barcode, Between, Ccnum, Date, Digits,
EmailAddress, Float, GreaterThen, Hex, Hostname, Iban,
InArray, Int, Ip, LessThan, NotEmpty, Regex, StringLength

<?php
$email = $this->getRequest()->getPost('email', 'none@example.com');

$validator = new Zend_Validate_EmailAddress();


if ($validator->isValid($email)) {
// email seems valid
} else {
// email seems invalid; Outputting the reasons
foreach ($validator->getMessages() as $message) {
echo "$message\n";
}
}
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  14


Chaining Validators

• for complex validations own validators can be implemented


• it is however possible to combine validators in validator chains

<?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";
}
}
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  15


Filtering with Zend_Filter

• Filtering of parameters is done with filters


• Zend-Framework comes with a set of pre defined filters
Alnum, Alpha, BaseName, Callback, Decrypt, Digits, Dir,
Encrypt, Htmlentities, Int, StripNewlines, RealPath,
StringToUpper, StringToLower, StringTrim, StripTags

<?php
$message = $this->getRequest()->getPost('message', '');

$filter = new Zend_Filter_StripTags();

// remove all tags


$message = $filter->filter($message);
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  16


Chaining Filters

• for complex filtering own filters can be implemented


• it is however possible to combine filters in filter chains

<?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);
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  17


Inputvalidation/-filtering in Forms (I)

• ZF-Forms use validators and filters automatically


• they are attached to Zend_Form_Element objects
• and can be chained as wished
// create name element
$name = $form->createElement('text', 'name', array('size' => 40, 'maxlength' => 40));
$name->addValidator('Alpha')
->addValidator('StringLength', false, array(1, 40))
->setLabel('Name')
->setRequired(true);

// create message element


$message = $form->createElement('textarea', 'message', array('rows' => 6, 'cols' => 40));
$message->setLabel('Message')
->setRequired(true)
->addFilter('StripTags');

// create submit button


$submit = $form->createElement('submit', 'send');
$submit->setLabel('send');

// add all elements to the form


$form->addElement($name)->addElement($message)->addElement($submit);

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  18


Inputvalidation/-filtering in Forms (II)

• Form is validated in the action handler

// checking form data for validity


if (!$form->isValid($this->getRequest()->getPost()))
{
// submit varibales to view
$this->view->form = $form;
$this->view->title = "Form 1";

// stop processing
return $this->render('form');
}

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  19


Validation and Filtering with Zend_Filter_Input

• is a framework for validation and filtering complete arrays


• applies defined filter and validation ruleset to supplied data
• allows validation of all user input automatically
$filters = array(
'*' => 'StringTrim',
'month' => 'Digits'
);

$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";
}

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  20


Part IV
SQL Security

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  21


SQL Security - Traditionally

• Traditional PHP Applications


• use PHP‘s database extensions directly
• use their own database abstraction layer
• use PDO
• lots and lots of different escaping functions
• escaping only supports data not identifiers
• partially support for prepared statements

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  22


Databaseaccess in Zend-Framewok Applications

➡ Zend-Framework offers different APIs for handling queries


• Zend_Db
• Zend_Db_Statement
• Zend_Db_Select
• Zend_Db_Table

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  23


Zend_Db - Queries (I)

• function query($sql, $bind = array())


• uses prepared statement internally
• SQL-Injection still possible if $sql is dynamically created
• function fetchAll($sql, $bind = array(), $fetchMode = null)
• all „fetch“ methods use prepared statements internally
• SQL-Injection still possible if $sql is dynamically created

<?php
$sql = "SELECT id FROM _users WHERE lastname=? AND age=?";
$params = array('Smith', '18');
$res = $db->fetchAll($sql, $params);
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  24


Zend_Db - Queries (II)

• function insert($table, array $bind)


• internally uses prepared statements
• SQL-Injection not possible

• function update($table, array $bind, $where = '')


• uses partially prepared statements
• SQL-Injection still possible if $where is dynamically created

• function delete($table, $where = '')


• SQL-Injection still possible if $where is dynamically created

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  25


Zend_Db - Escaping

• function quote($value, $type = null)


• applies the correct escaping - one function not many
• ATTENTION: also puts strings in quotes

• function quoteIdentifier($ident, $auto=false)


• applies escaping for identifiers
• a function not available to traditional PHP applications
• ATTENTION: also puts strings in quotes

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  26


Zend_Db_Select

• used to dynamically build SELECT statements


• uses partially prepared statements
• SQL-Injectionen still possible when wrongly used
• vulnerable through: WHERE / ORDER BY

// Build this query:


// SELECT product_id, product_name, price
// FROM "products"
// WHERE (price < 100.00 OR price > 500.00)
// AND (product_name = 'Apple')

$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);

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  27


Part V
Cross Site Request Forgery (CSRF) Protection

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  28


Cross Site Request Forgery (CSRF) Protection

• Protections against CSRF attacks are usually based on secret,


session depended form tokens

• Zend-Framework offers Zend_Form_Element_Hash which is a


secret token with built-in validator

• HTML forms can be secured against CSRF attacks by just adding


the form element to the form

$form->addElement('hash', 'csrf_token',
array('salt' => 's3cr3ts4ltG%Ek@on9!'));

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  29


Automatic CSRF Protection

• normally protection must be added manually


• by deriving Zend_Form it is possible to create an own form
class that automatically comes with CSRF protection

<?php
class My_Form extends Zend_Form
{
function __construct()
{
parent::__construct();
$this->addElement('hash', 'csrf_token',
array('salt' => get_class($this) . 's3cr3t%Ek@on9!'));
}
}
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  30


Token Algorithm

/**
• 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);
}

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  31


Part VI
Session Management Security

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  32


Session Management Configuration

• Configuration has big influence on security


• to safeguard SSL applications set the secure flag
• use an own session id for each application
• harden the session cookie against XSS with the httpOnly flag
• define the maximal lifetime
<?php
Zend_Session::setOptions(array(
/* SSL server */ 'cookie_secure' => true,
/* own name */ 'name' => 'mySSL',
/* own storage */ 'save_path' => '/sessions/mySSL',
/* XSS hardening */ 'cookie_httponly' => true,
/* short lifetime */ 'gc_maxlifetime' => 15 * 60
));
Zend_Session::start();
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  33


Session Fixation and Session Hijacking

• 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();

• should be added directly into the login functionality


• Session Hijacking
• there is only one real protection - SSL
• httpOnly cookies protect against session id theft by XSS
• session validation only of limited use

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  34


Session Validation (I)

• recognizes a valid session by checking certain additional


information stored in the session

• often recommended as protection against session fixation/hijacking


- but doesn‘t make much sense

• Zend-Framework supports session validators to validate sessions


• Zend_Session_Validator_HttpUserAgent

<?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());
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  35


Session Validation (II)

• Attention checking additional information can cause trouble


• User-agent HTTP header checking is dead since Internet Explorer 8
• Accept HTTP header checks have always been a problem with
Microsoft Internet Explorer

• Checking the client‘s IP address is a problem when big proxy farms


are used (big companies/ISPs)

➡ possible to limit to class C/B/A networks


➡ but useful for SSL applications

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  36


Session Validation - Validating Client‘s IP Address
<?php
class Zend_Session_Validator_RemoteAddress extends Zend_Session_Validator_Abstract
{

/**
* 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);

return $currentBrowser === $this->getValidData();


}

}
?>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  37


Part VII
Cross Site Scripting (XSS) Protection

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  38


XSS in Zend-Framework Applications

• Symfony supports automatic output escaping


• Zend-Framework doesn‘t support such automagic
• preventing XSS is job of the programmer
• XSS occurs in the „view“ part

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?php echo $this->title; ?></title>
</head>
<body>
<h2><?php echo $this->headline; ?></h2>
<ul>
<li><a href="<?php echo $this->link; ?>">Link 1</a></li>
</ul>
</body>
</html>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  39


Protecting against XSS (I)

• Two alternative traditional protections


1. Encoding before echoing

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?php echo $this->escape($this->title); ?></title>
</head>
<body>
<h2><?php echo $this->escape($this->headline); ?></h2>
<ul>
<li><a href="<?php echo urlprepare($this->link); ?>">Link 1</a></li>
</ul>
</body>
</html>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  40


Protecting against XSS (II)

• Two alternative traditional protections


2. Encoding when assigning template variables

$entityFilter = new Zend_Filter_HtmlEntities();


$urlFilter = new My_Filter_Url();

$this->view->title = $this->escape("Page 1");


$this->view->headline = $entitiyFilter->filter($this->getRequest()->getPost('link'));
$this->view->link = $urlFilter->filter($this->getRequest()->getPost('link'));

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  41


Protecting with Zend_View_Helper

• 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

<form action="action.php" method="post">


<p><label>Your Email:
<?php echo $this->formText('email', 'you@example.com', array('size' => 32)) ?>
</label></p>
<p><label>Your Country:
<?php echo $this->formSelect('country', 'us', null, $this->countries) ?>
</label></p>
<p><label>Would you like to opt in?
<?php echo $this->formCheckbox('opt_in', 'yes', null, array('yes', 'no')) ?>
</label></p>
</form>

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  42


Automatic Escaping by deriving Zend_View

• all output goes through Zend_View


• deriving Zend_View allows automatic encoding
• e.g. by overloading __set() and __get()
• Attention: Encoding must be context sensitive (e.g.: javascript: Links)

public function __get($key)


{
if (isset($this->_params[$key])) {
return($this->escape($this->_params[$key]));
}
return null;
}

public function __set($key, $val)


{
$this->_params[$key] = $val;
}

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  43


Thank you for listening...

Questions ?
http://www.sektioneins.de

Stefan Esser • Secure Programming with the Zend-Framework • June 2009 •  44

You might also like