Secure Programming With The Zend Framework

  • May 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Secure Programming With The Zend Framework as PDF for free.

More details

  • Words: 2,675
  • Pages: 44
http://www.sektioneins.de

Secure Programming with the Zend-Framework Stefan Esser <[email protected]>

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

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

Model

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 4. $_COOKIE

$message = $this->getRequest()->message;

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 getRequest()->getPost('email', '[email protected]'); $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 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

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 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

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 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 improved

• avoid mt_rand() • more entropy

• but it is safe enough (for now)

/** * Generate CSRF token * */ protected function _generateHash() { $this->_hash = md5( mt_rand(1,1000000) . $this->getSalt() . $this->getName() . mt_rand(1,1000000) ); $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

=> => => => =>

true, 'mySSL', '/sessions/mySSL', true, 15 * 60

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

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 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 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <?php echo $this->title; ?>

headline; ?>



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

Protecting against XSS (I)

• Two alternative traditional protections 1. Encoding before echoing <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <?php echo $this->escape($this->title); ?>

escape($this->headline); ?>



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



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

Related Documents