• Aucun résultat trouvé

t eMpl Ate S trAtegy p At ternS

The Template pattern is one of twenty-three design patterns outlined in the book Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, and Ralph Johnson (1994). This book focuses on the first pattern because the intent of the Template pattern is to enforce a series of steps. Enforcing a series of steps is an essential element of providing security. This makes the Template pattern a useful tool in architecting secure software.

Template Pattern Enforces Process

The Template pattern enforces process and a basic example of where the true useful-ness of this would occur in real world programming is the process of registering a user.

Registering a user requires a series of steps that must always be executed. Here, the logic is presented to architect this pattern in PHP. The focus is on architecting the pattern with language constructs of PHP. Chapter 15 implements an actual account management class that registers a user as a member.

In the design of this system, registration is a two-step process. Step one is to register the user, and step two is to activate the account.

Account Registration Template

The functions to implement the steps of this process would be:

1. validateRegistrationData() 2. createPasswordHash()

3. createActivationCode() 4. storeUserDataAsInactive() 5. sendRegistrationEmail()

After performing these steps, the account is inactive and cannot be logged into until the account it verified by processing the account activation code is sent to the user.

The process of activating the account is the design of a second Template pattern.

These functions always need to be called in this order for every registration. How do we enforce this behavior? This is the need that created the Template pattern. Here is how it is implemented in PHP.

abstract class AccountManagerBase {

//the registration process template function public final function processRegistration() {

$this->validateRegistrationData()

$this->createPasswordHash()

$this->createActivationCode()

$this->storeUserData()

$this->sendRegistrationEmail() }

//the registration implementation functions

abstract public function validateRegistrationData();

abstract public function createPasswordHash();

abstract public function createActivationCode();

abstract public function storeUserData();

abstract public function sendRegistrationEmail();

}

The primary elements here are the key words abstract and final. In PHP, adding abstract to a class definition or function declaration, means it must be implemented in the extending class. The key word final, added to the processRegistration() function, means that this function cannot be overridden by an extending class.

Final means these steps will be executed in this order. This is the desired effect. The AccountManagerBase class is now a process template. The AccountManagerBase class on its own cannot be implemented. No additional code will go here. Any class extending this class must implement every single one of the abstract functions or a run-time error will be generated, helping to enforce the design. This template class now outlines exactly the functions that need to be called and the order in which the steps need to occur. Perfect.

To implement this template and put it to actual use,

class AccountManager extends AccountManagerBase { function validateRegistrationData() {

//validate the user data echo "validating data...\n";

}

function createActivationCode() { //create the activation code

echo "creating activation code...\n";

}

function createPasswordHash() {

//create a hash of the password //we do not ever keep the original echo "creating hash...\n";

}

function storeUserData() {

//send this data to the database

//this creates the user account record echo "saving to database...\n";

}

function sendRegistrationEmail() { //send the user an email

//with the activation code to the registered email echo "emailing activation code...\n";

}}

//create a manager

$manager = new AccountManager();

//perform the entire registration process

$manager->processRegistration();

Program output:

validating data...

creating hash...

creating activation code...

storing to database...

emailing code...

Here the AccountManagerBase class has been extended by the AccountManager class in order to implement the registration template. Every abstract function has been implemented by force of the abstract key word directive. A new AccountManager object was instantiated, and the call to processRegistration() executed all the required steps. The result of this process is that there is now a new user with a registered but inactive account, who has an account activation mail in his email box.

Account Registration Template—Activation

Once the user decides to click the activation link in the email, the request needs to be processed in order to activate the account.

The functions to implement the steps of this process would be:

1. validateActivationLink()

2. updateSuccessfulActivationToDB() 3. sendAccountActivatedEmail()

After performing these steps, the user is activated and can login using the password he chose against the hash that was saved, and a welcoming activation confirmation email is sent to the user.

The code to implement these steps with the Template design pattern is as follows.

abstract class AccountManagerBase {

//the activation process template function public final function processActivation() {

$this->validateActivationLink();

$this-> updateSuccessfulActivationToDB ();

$this-> sendAccountActivatedEmail ();

}

//the activation implementation functions

abstract public function validateActivationLink ();

abstract public function updateSuccessfulActivationToDB ();

abstract public function sendAccountActivatedEmail ();

}

The full AccountManagerBase class is not printed here for brevity. The new template function and supporting implementation functions are simply added to the class.

To implement the class, the same procedure as for the registration process is followed.

class AccountManager extends AccountManagerBase { function validateActivationLink () {

//validate the link

echo "validating activation link...\n";

}

function updateSuccessfulActivationToDB () {

//update the account to activated, the user can login now echo "activating account...\n";

}

function sendAccountActivatedEmail () { //send user confirmation email

echo "sending account activated email...\n";

}

//create a manager

$manager = new AccountManager();

//perform the entire activation process

$manager->processActivation();

Program output:

validating activation link...

activating account...

sending account activated email...

The user is now activated and can log in to use the account using the password he chose.

It will be compared against the hash that was stored. A welcoming message is sent to con-firm the success of the process and to invite the user to log in and use this new account.

Strategy Pattern for Output Escaping

As we have seen, output context escaping is complex. A strategy is required to map an implementation to a specific output target. This makes it a prime candidate for the Strategy pattern. Based on output target, an implement needs to be created. PHP provides the language tools to structure a Strategy pattern.

Escaping Strategy Class

Listed here is a Strategy pattern that helps apply the correct escaping for the different display contexts.

<?php

//define constants to identify display contexts const HTMLOUT = 1;

const URLOUT = 2;

const BOTHOUT = 3;

//declare the output strategy class class OutputStrategy {

private $context;

//function that instantiates the needed strategy public function_construct($outputContext) {

switch ($outputContext) { case HTMLOUT:

$this->context = new displayHTML();

break;

case URLOUT:

$this->context = new displayURL();

break;

case BOTHOUT:

$this->context = new displayBOTH();

break;

}}

//implement the main interface function public function display($data) {

return $this->context->display($data);

}}

//define the interface to used by all strategies interface ContextInterface {

public function display($data);

}

//implement the first strategy that knows about HTML class displayHTML implements ContextInterface { public function display($data) {

echo htmlentities($data, ENT_QUOTES, "UTF-8");

echo "\n";

}}

//implement the second strategy that knows about URLs class displayURL implements ContextInterface {

public function display($data) { echo urlencode($data);

echo "\n";

}}

//implement the third strategy that knows about both HTML and URL class displayBOTH implements ContextInterface {

public function display($data) {

echo htmlentities(urlencode($data), ENT_QUOTES, "UTF-8");

echo "\n";

}}

//implement a wrapper class for raw data

//this façade gives the strategy objects in interface to act on class ProtectedData {

//create data objects, one with embedded single quote

$good = new ProtectedData("Tim O'Reilly");

$bad = new ProtectedData("Tom Riddle");

//instantiate several output strategies

$_H = new OutputStrategy(HTMLOUT);

$_U = new OutputStrategy(URLOUT);

$_B = new OutputStrategy(BOTHOUT);

//output the data objects via the correct strategy for the job

$_H->display($bad->getData());

$_U->display($good->getData());

$_B->display($good->getData());

?>

Raw program output:

Tom Riddle Tim+O%27Reilly Tim+O%27Reilly

The first name is unaltered, as there was nothing to escape for straight HTML context.

The second and third names contain escape sequences for URL and HTML. The space in the name has been replaced with a “+”. The single quote has been replaced with “%27”.

The OutputStrategy class creates a strategy implementation based on context.

The switch statement is used to make the decision about which strategy object to instantiate. It then stores this strategy internally. In this case, there are three strategy classes to choose from, displayHTML, displayURL, and displayBOTH. The class also implements a display function whose purpose is to activate the strategy when needed.

Next, an interface, ContextInterface, is declared so that all the strategy classes have a common interface, so they will be activated the same way regardless of who the activator is. This provides powerful decoupling of objects and functionality, allowing implementation changes to be made without breaking the code.

Next, each strategy is declared as implementing the ContextInterface interface, which forces each strategy to implement the display() function. This completes the framework which provides the generic functionality needed to achieve a flexible strategy choice.

Specific implementations are next. Each class, displayHTML, displayURL, and displayBOTH has a concrete implementation for its strategy. displayHTML has the job of securely escaping output for display in the HTML of a browser, so it calls any and all functions needed to prepare the data for this context. In this case, only htmlentities() is needed. displayURL needs to call urlencode() to prepare data and a URL parameter. displayBOTH is more complex in that it has the job of creating a safe link for use in an HTML page, so it needs to first call urlencode(), to escape the link, then send the output of that escaping process into htmlentities() which makes it safe for display in the HTML page. At this point data can be sent to the right strategy for safe output.

There is room for improvement in this class. First, the data object needs to get its own data, which makes for a verbose call. Second, greater flexibility is needed for other types of data objects that need to be safely displayed. This is accomplished with one improvement in the next section.

Improved Escaping Strategy Class

To improve the flexibility of our strategy class and increase the number of different types of objects that can be output via the strategy classes, an interface needs to be created and implemented by all data objects, as shown here.

<?php

//declare constants to identify the strategies const HTMLOUT = 1;

const URLOUT = 2;

const BOTHOUT = 3;

//declare the output strategy class class OutputStrategy {

//variable that hold the strategy object private $context;

public function display(IData $data) { return $this->context->display($data);

}}

//declare the interface needed by all strategy classes interface ContextInterface {

public function display(IData $data);

}

// implement the HTML output context strategy class which uses ContextInterface

class displayHTML implements ContextInterface { public function display(IData $data) {

echo htmlentities($data->getData(), ENT_QUOTES, "UTF-8");

echo "\n";

}}

// implement the URL output context strategy class which uses ContextInterface

class displayURL implements ContextInterface { public function display(IData $data) {

echo urlencode($data->getData());

echo "\n";

}}

//implement a strategy for both contexts which uses ContextInterface class displayBOTH implements ContextInterface {

public function display(IData $data) {

ec ho htmlentities(urlencode($data->getData()), ENT_QUOTES,

"UTF-8");

echo "\n";

}}

//declare the interface to be used by all data objects interface IData {

public function getData();

}

// implement the first type of data class which holds a single item of data

//implements IData so that it can be consumable by any strategy //this means it must implement getData()

class ProtectedInput implements IData { private $data;

// implement the second type of data class which holds two items of data

//implements IData so that it can be consumable by any strategy //this means it must implement getData()

class ProtectedRecord implements IData { private $name;

return $this->name. " ". $this->title;

}}

//instantiate completely different kinds of data objects

$userInput = new ProtectedInput("Tim O'Reilly");

$userRecord = new ProtectedRecord("Valantino Rossi",

"Seven Times World MotoGP Champion");

//instantiate strategies

$_H = new OutputStrategy(HTMLOUT);

$_U = new OutputStrategy(URLOUT);

$_B = new OutputStrategy(BOTHOUT);

// display completely different kinds of data objects safely depending on context

Raw output:

Tim O&#039;Reilly Tim+O%27Reilly

Valantino Rossi Seven Times World MotoGP Champion Valantino+Rossi+Seven+Times+World+MotoGP+Champion Output as displayed in HTML after browser parsing:

Tim O'Reilly Tim+O%27Reilly

Valantino Rossi Seven Times World MotoGP Champion Valantino+Rossi+Seven+Times+World+MotoGP+Champion

Now there are two different data classes that can be safely output via the strategy classes. This was accomplished through the usage of the new interface IData.

The protected data classes implement IData, which gives them a common method to be acted upon. Each data class has its own implementation, which knows the details about the data it is holding. The interface, IData, makes it accessible to the strategy classes.

IData has also been added as parameter type to the display() method ContextInterface in this manner: display(IData $data). This enforces type checking and ensures that only protected data objects are sent and received by strategy objects. This is how the PHP language construct provides a great deal of assistance for enforcing design procedures. Procedure enforcement is good for security.

The Input Cleaner Class

This class makes use of variable variables to automate the process of sanitizing all input from $_POST or $_GET arrays as UTF-8 compliant strings. This process examines every incoming string for UTF-8 compliance, and converts any invalid characters via replacement, with a U+FFFD character. This is a potentially destructive process, but for legitimate users, incoming data should already be UTF-8 compliant, and not an issue.

Then every key and value is sanitized and validated according to a mapped member function array. This array tells the Cleaner class which keys are required for this script, and maps a validation function for that key’s variable. All other keys are eliminated, along with the super global array, making raw, potentially unsafe data inaccessible.

Variables can now only be accessed by the public function getKey(), which will either return a valid, sanitized value as specified by the function mapping, or a false value.

Just the step of ensuring all data is UTF-8 goes a long way toward increasing secu-rity. Aside from performing the critical base step, the Cleaner class also forces early stage variable design to take place. In order to be useful, the data, the types, and the validation functions need to be planned in advance. Variables used in the script needs to be declared in the validation array at the top of the script, which prevents arbitrary variable usage later. This promotes a more secure design.

<?php

//make incoming array private to protect contents foreach($input as $key = > $field)

{

//ensure each string is valid UTF-8 before testing //replace invalid characters with U+FFFD character

$t his->data[$key] = mb _ convert _ encoding($field, 'UTF-8', 'UTF-8');

}

//destroy the original to make it publicly inaccessible

$input = null;

}

public function setValidators($required_fields) {

foreach($required_fields as $key = > $field) {

//check incoming array against the required array //only keep data we want

//assign the incoming element key //1) a filter function

//2) the incoming value

if(array_key_exists($key, $this->data)) {

// this creates an element key name that the main program wants to reference

//and assigns it a filter function and the value

$t his->data[$key] = array($required_fields[$key],

$this->data[$key]);

//Make sure the array key exists

if(array_key_exists($key, $this->data)) {

//get the filter function bound to this key

$filterFunction = $this->data[$key][0];

if(method_exists($this, $filterFunction)) {

// use a Variable Variable to assign dynamic string name to function

//This will call the filter function bound to this variable

$filtered = $this->$filterFunction(

$this->data[$key][1]

);

//return filtered input data

//data was filter according to the required array parameters return $filtered;

return mb_substr(filter_var($var, FILTER_SANITIZE_STRING), 0, 12);

}

private function getSelfFUNCTION ($key = "") {

//this function makes certain that the

//POST variable name MATCHES the POST variable value return ($key = = = $this->data[$key][1]) ? $key : "";

} }

First, make sure that the UTF-8 replacement character is correctly configured for any conversion that needs to occur with mb_substitute_character().

The only member variable in the class is an array, $data, and it is private. This is done to force access through the getKey() function. This array holds the key/value pairs needed for this script.

setData() is the sanitization function for UTF-8 compliance. This function pro-cesses every incoming string and ensures they are entirely comprised of valid UTF-8 characters. Notice that the incoming array is passed by reference. This is how it is destroyed by setting it to null.

foreach() loops through each key and checks the field string value.

foreach($input as $key = > $field)

Here each string that contains invalid UTF-8 characters will have those characters replaced inline with the character, U+FFFD, which was set via mb_substitute_character().

$this->data[$key] = mb_convert_encoding($field, 'UTF-8', 'UTF-8');

After sanitization, each key/value pair is assigned to the private $data variable.

This action explicitly makes a sanitized UTF-8 copy of the original array.

The following line destroys the original by setting the reference to null, in order to make it publicly inaccessible in the future.

$input = null;

The functions of primary interest are setValidators(), getValue(), and getSelf().

1. setValidators() loops through the validation array, comparing it to the private $data array. Any data in private $data that does not exist in the validation array is eliminated, as it is not needed by this script.

2. getValue() checks to see if the requested key exists, and if it has a value, if not, it returns false, and is a very safe way for checking for value.

3. getSelf() is interesting. It gets a key whose value is equal to the key name.

This is useful for easily checking that an incoming string is equal in both value and type to a constant. In this case that ‘reAuthorize’ = = = ‘reAuthorize’. Note the triple equal signs.

Note: If the key requested actually needs to have a value of true or false, change the return type.

setValidators() uses the following line to detect and assign what data should be there by comparing the validation array to the private copy of the original data.

if(array_key_exists($key, $this->data)) {

$this->data[$key] = array($required_fields[$key], $this->data[$key]);

}

getSelf() depends on the following line to test that a key name is equal in type and value to the key name, and returns false if not.

return ($key = = = $this->data[$key][1]) ? $key : "";

getKey() is more complex. It does two things: looks to see if the key exists, and then looks up the validation function for the key. If the validation function exists, the data for the key is passed to that function for processing and returned.

First, check if the key exists in the array. This improves design and prevents arbitrary variable usage. Variables needed by the script must be included in the validation array.

if(array_key_exists($key, $this->data))

Second, the validation function assigned to the key is obtained.

$filterFunction = $this->data[$key][0];

Third, check to see that the validation function assigned to the key is actually a member of the Cleaner class. This prevents calling a function that does not exist.

if(method_exists($this, $filterFunction))

Fourth, a variable variable is used to actually call the filter function bound to this vari-able. Note the double $ usage. This maps a dynamic string name to an actual function.

$filtered = $this->$filterFunction($this->data[$key][1] );

Finally, the filtered, validated, and sanitized data is returned. This is on-demand validation.

return $filtered;

Testing the Cleaner Class

Set up a test array to mimic incoming $_POST/$_GET data. This example contains

Set up a test array to mimic incoming $_POST/$_GET data. This example contains