• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Creating "Secure" PHP Applications, Part 1, Explicit Code & QA

Creating "Secure" PHP Applications, Part 1, Explicit Code & QA






Total Views
Views on SlideShare
Embed Views



1 Embed 2

https://si0.twimg.com 2



Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

    Creating "Secure" PHP Applications, Part 1, Explicit Code & QA Creating "Secure" PHP Applications, Part 1, Explicit Code & QA Presentation Transcript

    • Explicit Code & QA
    • So, who are you, anyway? Bryan C. Geraghty Security Consultant at Security PS @archwisp I’m a Sr. PHP developer with a systems and security engineering background - turned application security consultant
    • Remember, layersSimpler is easier to testDon’t make assumptionsCompromised browser = game over
    • These are not specifically security activities but they produce morestable code
    • Don’t rely on the server’s configuration Your bootstrap should Absolute Minimum set the defaults for any  Include paths PHP core functionality  Error reporting that your application is  Time zones using. These must be customizable for every environment e.g. (dev, staging, live)
    • Example Bootstrap<?php// All environment configuration for this application is done from this fileini_set(display_errors, 0);ini_set(error_reporting, -1);date_default_timezone_set(UTC);$rootPath = dirname(__FILE__);set_include_path(sprintf( %s%s%s%s, $rootPath, PATH_SEPARATOR, $rootPath, /third-party));require_once(MindFrame2/AutoLoad.php);MindFrame2_AutoLoad::install();
    • Don’t use global constants, variables, or registries You can’t be certain that nobody else will ever use the same global constant name Tracking down where a value is assigned to a global variable is usually very difficult Global variables remove control of that variable from the current scope Global registries are really just fancy global variables and the same problems apply
    • Value Reference Rules Values should only be referenced in one of the following ways:  A direct reference in the current scope: $limit = $this->_objectPool->getConfig()- >getDefaultLimit();  A parameter: public function getUsers($limit) { return $this->_objectPool- >getMapper(‘User’)->fetchAll($limit); }
    • Don’t use function parameter defaults "There should be one-- and preferably only one -- obvious way to do it." - Tim Peters Reduces understanding from the caller perspective Often add unnecessary complexity Represents the most common use-case Other use-cases are often ignored entirely Changing the default breaks all implementations Adding parameters breaks default implementations
    • Default parameter exampleclass User{ public function __construct($name, $email, $status = self::STATUS_ACTIVE) { $this->_name = $name; $this->_email = $email; $this->_status = $status; }}function createUser($name, $email, $status) { $user = new User($name, email); return $this->_objectPoool->getMapper(‘User’)->create($user);}
    • Use explicit operators whenever possibleThis was actual production code.if ($sincedate && (int)$sincedate) { $param["UpdatedSinceDate"] = date("Y-m-d H:i:s", strtotime(time() - ((int)$sincedate)*60*60);} elseif ($sincedate && strtotime($sincedate)) { $param["UpdatedSinceDate"] = date("Y-m-d H:i:s", strtotime($sincedate));} elseif(!isset($param["UpdatedSinceDate"])) { exit ("Invalid param UpdatedSinceDate");}Do you think this code worked as the author intended when $sincedate was set to2011-05-31?
    • Use constants for possible valuesConstants cannot be re-defined, so using a constant for configuration limits your codeto only ever be able to run in one configuration in a given stack.// Bad: This code cannot execute differently in the same stackdefine(‘PDO_FETCH_MODE’, 2);$dbi->fetchAll(PDO_FETCH_MODE);// Better: The value can change but this literal value means nothing without// referencing the documentation$dbi->fetchAll(2);// Best: Implemented using a meaningful constant which represents a *possible* value$dbi->fetchAll(PDO::FETCH_ASSOC);
    • Use wrappers for super-globals $_REQUEST, $_GET, $_SESSION, and $_FILES are the most commonly used PHP super-globals but there are others It’s easy to create some serious security problems It’s best to use a wrapper for interacting with these variables
    • Simulate strong/static typesPHP is dynamically typed, so we cannot do true strong or static typing but we canput controls in place which provide the same protection.private function _buildSelectDatabaseTableSql($database_name, $table_name, array $select_data, array $order_by_columns, $offset, $limit) { MindFrame2_Core::assertArgumentIsNotBlank($database_name, 1, database_name); MindFrame2_Core::assertArgumentIsNotBlank($table_name, 2, table_name); MindFrame2_Core::assertArgumentIsInt($offset, 5, offset); MindFrame2_Core::assertArgumentIsInt($limit, 6, limit); $skel = "SELECTn %snFROMn %s.%sn%s%s%s%s;"; $sql = sprintf($skel, $this->_buildSelectTableSqlFieldClause($table_name), $this->getSharedModule()->escapeDbElementName($database_name), $this->getSharedModule()->escapeDbElementName($table_name), $this->_buildSelectTableSqlJoinClause( $this->getSharedModule()->getDatabase()->getName(), $table_name), $this->_buildSelectTableSqlWhereClause($table_name, $select_data), $this->_buildSelectTableSqlOrderByClause( $table_name, $order_by_columns), $this->_buildSelectTableSqlLimitClause($offset, $limit)); return $sql; }
    • Example Typing Assertionspublic static function assertArgumentIsInt($value, $position, $name){ if (!is_int($value)) { $skel = Expected integer value for argument #%d (%s), %s given; $message = sprintf($skel, $position, $name, gettype($value)); throw new InvalidArgumentException($message); }}public static function assertArgumentIsNotBlank($value, $position, $name){ if (trim($value) === ) { $skel = Argument #%d (%s) cannot be blank; $message = sprintf($skel, $position, $name); throw new InvalidArgumentException($message); }}
    • Use PHPMD & CodeSnifferThis is the ./bin/codecheck script in MindFrame2#!/bin/bashWD="`/usr/bin/dirname $0`/../";echo Changing to working directory: $WD;cd $WD;if [ -z $1 ]; then DIR=.;else DIR=$1;fiphpmd --exclude coverage $DIR text codesize,unusedcode,naming,designphpcs --ignore=coverage --standard=`pwd`/Standards/MindFrame2 $DIRphpcs --ignore=coverage --report=source --standard=`pwd`/Standards/MindFrame2 $DIR
    • Example PHPMD Outputbryan@ubuntu-virtual ~/Code/MindFrame2 [130] $ ./bin/codecheck Dbms/DbiChanging to working directory: ./bin/..//home/bryan/Code/MindFrame2/Dbms/Dbi/Distributed.php:128 Avoid unused localvariables such as $partner./home/bryan/Code/MindFrame2/Dbms/Dbi/Distributed.php:185 Avoid unused localvariables such as $data./home/bryan/Code/MindFrame2/Dbms/Dbi/Distributed.php:199 Avoid unused localvariables such as $index./home/bryan/Code/MindFrame2/Dbms/Dbi/Distributed.php:240 Avoid unused privatemethods such as _buildReplicaDatabaseSuffix./home/bryan/Code/MindFrame2/Dbms/Dbi/Single.php:25 This class has too manymethods, consider refactoring it./home/bryan/Code/MindFrame2/Dbms/Dbi/Single.php:150 Avoid unused parameters such as$options.
    • Example PHPCS OutputFILE: /home/bryan/Code/MindFrame2/Dbms/Dbi/Single.php--------------------------------------------------------------------------------FOUND 6 ERROR(S) AFFECTING 6 LINE(S)-------------------------------------------------------------------------------- 39 | ERROR | Public member variables ("_connection") are forbidden 62 | ERROR | Whitespace found at end of line 144 | ERROR | Whitespace found at end of line 160 | ERROR | Line exceeds maximum limit of 80 characters; contains 97 | | characters 195 | ERROR | Whitespace found at end of line 298 | ERROR | Line exceeds maximum limit of 80 characters; contains 81 | | characters--------------------------------------------------------------------------------
    • Unit testing / TDD Test critical functionality at a minimum Add edge cases to regression tests as they are discovered Test-driven development only works if the entire team is dedicated to it I personally don’t trust code that isn’t regression-tested; even if it was written by me
    • Continuous Integration Automated system for code analysis and regression testing There are a lot of continuous integration systems for PHP If your tests aren’t automated, very few people will know or care when they break
    • Deployment Manually copying files is riddled with problems Tagging releases and re-deploying is a complicated and time-consuming process Deployment systems automate the build and deployment process
    • ACLsMACThread limitsUnwanted services
    • If you’re interested in an application security career, come talk withme.