• Aucun résultat trouvé

pHp S ecurIt y t oolS o vervIe W

PHP has many built-in tools that can be leveraged for secure coding. This chapter gives an overview of these tools and serves as an introduction to why they are used in building the secure application example code in the second part of the book. Many of the tools outlined here are viewed from a security perspective, so examples are given as to why they are important and how they can be leveraged to achieve more secure code.

Object Language Support

PHP is a procedural language and/or an Object-Oriented (OO) language. A developer can use the language either way, or in a mixture of ways. The languages object con-structs are a great way to encapsulate and isolate functionality. In this chapter we look at how to make use of the many OO features to enhance and enforce security.

The class construct is the basic building block to group related functionality together. Objects are the classes come to life, once the script starts running, to get the work done. The way these classes are organized and the way objects interact have a great impact in security. Some thought spent during design time goes a long way toward making the application more secure, as well as simplifying the code. The sim-pler the code can be, the easier it is to make it secure and to inspect from a security standpoint. Conversely, less clear code becomes harder to access easily. The key here is easily. The question is how much time does one want to spend looking for problems?

A famous quote from Brian Kernighan, who helped build Unix and was a coauthor of the first programming book for the C language, is “Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as pos-sible, you are, by definition, not smart enough to debug it.”

With that in mind, this book strives to keep things as simple as possible, in a clear style so that spotting problems becomes easier, instead of more difficult.

Abstract Classes, Interfaces, Façades, Templates, Strategy, Factories, and Visitors

Design Patterns: Elements of Reusable Object-Oriented Software (Gamma et al., 1994) introduced software communication to the world of developers. This book is pop-ularly known as the Gang of Four book. Design patterns are an essential tool for object-oriented software. The reason is that design patterns nicely abstract common interactions and functionality which allows developers to describe software. If design patterns are understood by a team, then one developer says to another team member,

“I need a factory,” and it is understood what code should be written. Design patterns are not a concrete implementation. There is no single factory code base of reusable functions. Instead, there is general pattern idea that describes what a factory should do and the basic functionality it should have. When a teammate delivers an implanted factory to the team it is nice to know that code produces automobile objects but is not an automobile itself.

There are 23 general design patterns described in Design Patterns. Several of them can be leveraged to achieve better security coding practices. The Singleton pattern is easily the most famous. The concept of a single, global application object t is easily understood and incorporated. The Singleton is an important architectural element and serves a powerful purpose in security development. This book uses this pattern frequently because it consolidates code, and is easy to use.

There are other design patterns that are less well known, especially, it seems, in the area of secure programming, and these patterns are demonstrated in a secure design intended to simplify and enforce security procedures. The following patterns can be very useful, and therefore this book uses them for securing code. They are, in no particular order, Abstract Classes, Interfaces, Façades, Template Functions, Strategy, Factory and Builder Patterns, and Visitors.

Abstract classes are important because they define functional behavior, but not implementation. An array might need to have a validate function, and a user object might need a validation function, but each will have a different way it needs to be done. However a caller of the object doesn’t want to know about that difference.

Abstract classes help achieve that.

Interfaces are very useful from a security perspective, as they decouple communica-tion and implementacommunica-tion between objects. With Interfaces, different objects with the same interface can be passed to the same functions for processing. For example, giv-ing a group of different objects an encryption interface, IEncrypt, means that those objects could all be called and encrypted in simple loop by a single function which expects objects with an IEncrypt interface, such as doEncrypt(IEncrypt $obj). Separating the call for encryption from the exact implementation of the encryption provides secure flexibility which we examine later.

Façades, universally known as wrappers, provide a much needed way to simplify function calls and help reduce repletion. The isolation they provide helps to enable separation of duties, such as keeping PHP out of HTML as much as possible.

Template patterns are enforcers; they ensure that certain steps are taken together as a sequence, while at the same time decoupling the implementation. Input filtering is a good example of where Templates can be very powerful for controlling validation and filtering. Templates in PHP are based on the keyword final. Here is an example as it could relate to a secure procedure.

abstract class TemplateStringValidator { ///function must be overridden

abstract function checkUTF8($obj);

//function must be overridden,

abstract function validateSize($obj);

//function must be overridden,

abstract function validateAllowedChar($obj);

//template method - keyword FINAL

//enforces that all algorithms are called public final function validateData($obj) { //final means cannot be overridden or changed //this validation order will be followed checkUTF8($ob);

validateSize($ob);

validateAllowedChar($obj);

} }

class Validator extends TemplateStringValidator { private function checkUTF8($obj)) {

//call the template function – enforce defined procedure

$validObj->validateData($$_POST['userName']);

Here there is an Abstract class, TemplateStringValidator, which means it cannot be instantiated. It has three abstract functions defined, which means that the class that extends this one must implement those functions. The abstract keyword enforces that behavior. The final function is the Template, which cannot be overridden.

Its purpose is to define the procedure, or sequence of functions, that are always to be called in a particular order.

The private and public keywords enforce a private implementation and a public capability. Finish this off with a PHPUnit test case and you have the makings of a very thorough and secure input validation system.

Strategy patterns can be leveraged to build proper output context for data.

Depending on whether a variable needs to be constructed for an output context of a HTML, or a URL, a different strategy is needed to put it together safely.

Factories and Builders can be leveraged to create input validation object rules, and output escaping rules.

Visitors might be the least well-known design pattern, but can be very effective in a secure design because they allow for different functionality to be achieved via the same interface.

These patterns are described in more detail later. The implementation of these patterns should be easy enough to understand within the context of this book if you already have PHP experience. For in-depth understanding and for additional design application, please read the original Design Patterns book (Gamma et al., 1994).

Variable Variables: Power DRY

Repetition is to be avoided in programming. Repetition easily induces mistakes, is a cause of hard-to-find bugs, and increases the difficulty and time required to make changes. The acronym DRY stands for Don’t Repeat Yourself and is an important ideal to cling to when designing and writing code. The idea is that when you find yourself repeating a statement, it should trigger an automatic response in your thought pro-cess that refactoring needs to occur right away in order to eliminate the duplication.

PHP has a powerful feature to help fight repetition called a variable variable. What this does is allow a variable to declare another variable instead of being limited to holding only a value. This means that a variable can hold the name of another variable and be used to reference that other variable. This mechanism creates a powerful and dynamic variable mapper which is best demonstrated with an example common to every PHP web application.

The traditional method:

$userName = validateInput($_POST['userName']);

$userPass = validateInput($_POST['userPass']);

$userEmail = validateInput($_POST['userEmail']);

$userBlogPost = validateInput($_POST['userBlogPost']);

While this is one of the most common ways to process input, the repetition here is painfully obvious. In order to achieve DRY status, we need a way to avoid this repeti-tion. This can be accomplished using PHP variables variables.

Improved DRY method:

$user = new secureUser();

foreach($_POST as $key = >$val) {

//note the use of double $ for Variable Variables

$user->$key = validateInput ($val);

}

echo htmlentities($user->userName, ENT_QUOTES, "UTF-8");

Notice the complete lack of repetition. In fact, every duplicated item, the variable names, $_POST array references, and functions calls to validateInput () have been eliminated. The magic for this occurs because of the use of the two $ signs for the user object. Normally, there would be just one,

$user->key

which would refer to a specific key.

This code uses two of them, one for each part,

$user->$key

which allows the key, now a variable variable, to refer to different keys in the array as we loop through each array pair.

What this functionality does is this. For the first iteration of the loop,

$user->$key = validateInput($val);

translates to become:

$user->userName = validateInput("Jack");

For the second iteration,

$user->$key = validateInput($val);

becomes

$user->userPass = validateInput("secretPassword!");

Each pass adds the correctly named variable and its value to the user object. In this case, there is now a new class member variable named “username”, which we can directly pass to htmlentities() before echoing out safely to the browser.

echo htmlentities($user->userName, ENT_QUOTES, "UTF-8");

Native Function Support Encoding Functions

This is the group of functions that are the workhorses for escaping output into the appropriate context.

HTML Encoding Explicit use of HTML encoding is used so that all environment conditions are accounted for. This includes specifying the character encoding as UTF-8, and that both single and double quotes are to be escaped.

htmlentities($output, ENT_QUOTES, "UTF-8");

Another useful but often overlooked example is explicitly setting the double_

encode flag to false, which prevents existing encodings from being double encoded.

By default, existing entities are double encoded, which is not usually desirable. This can be useful when parsing external RSS feeds that might already be encoded.

htmlentities($output, ENT_QUOTES, "UTF-8", false);

URL Encoding Sending a URL with embedded spaces can cause the URL to be truncated and the intended URL to not be reached. It is important to make sure that URLs are properly encoded so that spaces are converted to the proper entity, preserv-ing the full URL.

With PHP, there are two choices of encoding. Spaces can be converted to a plus sign, ‘+’, or to ‘%20’.

urlencode()/rawurlencode() Example The first example shows the effect of urlencode() to encode spaces as +.

$u rl = "https://www.security.com/index.php?file = learning security";

$encodedURL = urlencode($url);

echo $encodedUrl;

OUTPUTS:

https%3A%2F%2Fwww.security.com%2Findex.php%3Ffile%3Dlearning+security echo urldecode($encodedUrl);

OUTPUTS:

https://www.security.com/index.php?file = learning security The second example uses rawencode to encode spaces as %20.

$u rl = "https://www.security.com/index.php?file = learning security";

$encodedUrl = rawurlencode($url);

echo $encodedUrl;

OUTPUTS:

ht tps%3A%2F%2Fwww.security.com%2Findex.php%3Ffile%3Dlearning%20 security

echo rawurldecode($encodedUrl);

OUTPUTS:

https://www.security.com/index.php?file = learning security

parseurl() Example Being able to parse URLs and examine the individual parts can be a very important security task. parseurl() is a handy tool for breaking apart a URL into named sections.

$urlParts = parse_url('http://www.security.com/');

$urlParts = parse_url('https://www.security.com/');

$urlParts = parse_url("https://www.security.com/file.php");

$urlParts = parse_url("javascript:badfunction");

print_r($urlParts);

Array

( [scheme] = > http

[host] = > www.security.com [path] = >/

) Array

( [scheme] = > https

[host] = > www.security.com [path] = >/

) Array

( [scheme] = > https

[host] = > www.security.com [path] = >/file.php

)

The above printouts show the URLs broken out. This is useful for tests such as  the  following, where the scheme can be tested for a disallowed protocol, JavaScript,

if($urlParts[scheme] = = 'javascript') tossURLaway();

or to ensure that a protocol is being used, if(($urlParts[scheme] = = 'https') sendToOutput();

DRY Enforcement Functions

These are functions that automate the processing of arrays and can greatly reduce redundant code.

array_map() array_map() applies a callback to each element of an array.

array_map() returns an array containing all the elements after applying the call-back function to each one.

$dbResult = array( 'input1', 'input2', 'input3', 'input4' );

//function called for each array element

function removeChar(&$item, $key) { //remove character

}

//process the entire array

//send each item to removeChars()

$alteredArray = array_walk($dbResult, 'removeChars);

array_walk() array_walk() applies a user-defined function to every element of an array. Only the values of the array may be changed. Element order cannot be altered. Returns TRUE on success or FALSE on failure.

$dbResult = array( 'input1', 'input2', 'input3', 'input4' );

//function called for each array element function checkRanges(&$item, $key, $limit) {

//check range against limit

//replace item via reference if desired }

//process the entire array

//send each item to checkRanges()

array_walk($dbResult, 'checkRanges', MAXRANGE);

A few differences between the two are:

• array_map() never alters its arguments; array_walk() can.

• array_map() cannot operate with the array keys; array _ walk() can.

• array_map() returns an array; array_walk() returns true/false on success/failure.

• array_map() can process any number of arrays; array_walk() only one.

• array_walk() can take an extra parameter to pass to callback.

Type Enforcement Functions

Type enforcement functions are those which identify and/or convert data to required type. If a query requires an integer for an ID lookup, validation should ensure that ID is an integer only.

intval() and casting (int) versus ctype_alnum() and ctype_num() The three functions can be used very effectively for validation user input. Intval() and the cast operater, (int) actually convert strings into actual integers that can be depended upon to be safe afterwards.

Usage is:

$actualInt = intval($stringInt);

$actualInt = (int)$stringInt.

The PHP ctype functions, ctype_alnum(), and ctype_num() are useful for testing a string for valid character types. These functions do not convert; they simply test. If the test is positive, then the string is ensured to contain only numbers 0–9, or only number and letters, a–z, A–Z.

Usage is

if(ctype_alnum($userID)) {

$validID = $ userID;

} OR

if(ctype_num($id)) {

$numericID = $id;

}

Filter Functions

The PHP filter family of functions has a great many options for validating data.

The implementation of the functions depends on the type of flags passed in as the filter option, and there are two main flavors of filter flags, FILTER_VALIDATE and FILTER_SANITIZE. The difference is that using the FILTER_VALIDATE flag tests for condition, and FILTER_SANITIZE performs destructive data conversion.

These functions can be quite verbose, so wrapper shortcuts, or façades, are very helpful for using these functions inline when needed.

The benefit of the verbosity of these functions is that they are specific, which can be incredibly important. Examples of this are:

filter_var($number,FILTER_VALIDATE_INT) filter_var($number,FILTER_VALIDATE_FLOAT) filter_var($number,FILTER_VALIDATE_BOOLEAN)

which is more verbose that intval(). But when the specification requires it, these are very important distinctions.

filter_var() Functions FILTER_VALIDATE_INT: Test if string is a valid inte-ger value or not. Will return true or false.

$integer = '121212';

if(filter_var($integer,FILTER_VALIDATE_INT)) { echo 'Is integer';

}

$integer = '121212' will pass.

$integer = '121212.12' will fail.

FILTER _ VALIDATE _ FLOAT: Test if string is a valid float value or not.

Will return true or false.

if(filter_var($float,FILTER_VALIDATE_FLOAT)) { echo 'Is Float';

}

$float = '1.234' will pass.

$float = 'Attack' will fail.

FILTER _ VALIDATE _ BOOLEAN: Test if string is a valid Boolean value or not.

Will return true or false.

if(filter_var($bool,FILTER_VALIDATE_BOOLEAN)) { echo 'Is Boolean';

}

$bool = TRUE will pass.

$bool = 123 will fail.

FILTER_VALIDATE_EMAIL: Test if string is a valid email format or not. Will return true or false. There is not a check for actual email existence.

if(filter_var($email,FILTER_VALIDATE_EMAIL)) { echo 'Is valid email format';

}

$email = 'user@test.com will pass.

$email = 'AhabATshipDotcom' will fail.

FILTER _ VALIDATE _ URL: Test if string is a valid URL format or not.

if(filter_var($value01,FILTER_VALIDATE_URL)) { echo 'TRUE';

}

$url = 'http://www.test.com' will pass.

$url = 'test' will not pass.

Using the Sanitization Flags FILTER_SANITIZE_NUMBER_INT: Removes invalid numeric characters.

$untrusted = '888<script>alert(1)</script>';

$integer = filter_var($value01, FILTER_SANITIZE_NUMBER_INT);

output is: 888

FILTER_SANITIZE_EMAIL: Removes all invalid characters from email address string as determined by the email specification. Allowable, and valid email characters, are still dangerous in a SQL context, so email must be escaped for SQL.

$untrusted = 'user(5)@test.com';

$sanitizedEmail = filter_var($untrusted, FILTER_SANITIZE_EMAIL);

output is: user@test.com

FILTER_SANITIZE_STRING: Removes invalid data from string.

$untrusted = '<script>alert('Attack');</script>';

$safe = filter_var($untrusted, FILTER_SANITIZE_STRING);

The script tags are removed, and output is: alert(‘Attack’)

FILTER_SANITIZE_ENCODED: Encodes dangerous script tags in string.

$untrusted = '<script>alert('Attack');</script>';

$safe = filter_var($untrusted, FILTER_SANITIZE_ENCODED);

Encodes all punctuation, spaces, and angle brackets into HTML entities.

Output is:

%3Cscript%3Ealert%28%27ATTACK%27%29%3B%3C%2Fscript%3E

FILTER_SANITIZE_SPECIAL_CHARS: HTML encodes special characters like quotes, ampersands, and angle brackets.

$untrusted = '<script>alert('Attack');</script>';

$encoded = filter_var($untrusted, FILTER_SANITIZE_SPECIAL_CHARS);

Output is that special characters are encoded into their HTML enitities.

&#60;script&#62;alert(&#39;ATTACK&#39;);&#60;/script&#62;

strip_tags()

strip_tags() is used to remove HTML tags from a string. It can also remove PHP tags. But common usage is for HTML tags. The function is marginally depend-able to use as long as the ‘allowable_tags’ parameter is not used, and if the HTML is well formed. Marginally dependable means not dependable for security uses. It can-not be counted on to be completely safe for sanitization purposes. Telling strip _ tags() to keep some tags opens a large security hole. The hole is that tag attributes are preserved in the allowed tag. They are not filtered out, which allows executable code to be set by user input. The most common example is the insertion of the attribute, onMouseOver event handler, to become part of the HTML, which is very dangerous.

<b onMouseOver = "document.location = 'http://evilurl.com';"/>Hi!</b>

The other chief concern about strip_tags() is its behavior on malformed HTML, such as when a user forgets a closing tag. Strip_tags() becomes destruc-tive in that case and user data is lost. This may or may not be a problem depending on application design.

• OK if used without allowable tags.

• Destructive on malformed HTML.

• strip_tags() very dangerous when used with allowable_tags.

Dangerous—allows HTML attribute manipulation:

strip_tags($html, "<strong>");

Useful on well formed HTML:

strip_tags($html);

Well formed does not mean safe. Well formed simply means the HTML is for-matted correctly. Even attack strings can be forfor-matted correctly. The danger is when attack strings are not well formed in order to evade filtering. This is where strip_

tags() can come up short and should not counted on.

The best use of strip_tags() is for helping remove HTML from input for a business reason, not for a security reason.

Mobile Functions

Output buffering and output compression seem to be little known capabilities of PHP.

Output buffering and output compression seem to be little known capabilities of PHP.