• Like
Creating "Secure" PHP Applications, Part 1, Explicit Code & QA
Upcoming SlideShare
Loading in...5
×

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

  • 2,017 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
2,017
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
4
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Explicit Code & QA
  • 2. 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
  • 3. Remember, layersSimpler is easier to testDon’t make assumptionsCompromised browser = game over
  • 4. These are not specifically security activities but they produce morestable code
  • 5. 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)
  • 6. 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();
  • 7. 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
  • 8. 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); }
  • 9. 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
  • 10. 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);}
  • 11. 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?
  • 12. 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);
  • 13. 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
  • 14. 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; }
  • 15. 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); }}
  • 16. 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
  • 17. 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.
  • 18. 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--------------------------------------------------------------------------------
  • 19. 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
  • 20. 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
  • 21. 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
  • 22. ACLsMACThread limitsUnwanted services
  • 23. If you’re interested in an application security career, come talk withme.