Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Simple Techniques to Lock Down your Website

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

One crucial part of PHP development practice is always keeping in mind that security is not something you can simply buy off the shelf at your local convenient store. Ensuring the security of your web applications is a process, which over time, needs to be constantly evaluated, monitored, and hardened.


Introduction

While the use of filters and validating data is one part of the security process, a web developer should be aware that Randomization, Obfuscation, and Cryptography in PHP can make a difference in the security of web applications. This tutorial will guide you through some simple techniques at creating and using random or unique values within your web applications, taking a look and applying some general obfuscation techniques, and looking deeper into the science of Cryptology and it's use within PHP.


What you Will Learn

  • How to generate random values with PHP
  • Generating random Passwords
  • Salting Passwords and Authenticating The User
  • Obfuscation in PHP, an Overview
  • Cryptography in PHP and it's Applications

Generating Random Values

Dictionary.com defines randomization as:

"-verb: to order or select in a random manner, as in a sample or experiment, especially in order to reduce bias and interference caused by irrelevant variables; make random."

Random number generation is determined in a variety of ways, however computational generators fall short of 'true' randomness as seen in nature or electronic noise(the fuzzy, screeching, black and white channel on TV). These computed values are regarded as pseudo-random.

PHP provides us with a couple of different ways to create random values. Let's look at a few of the more popular functions.

<?php
rand(int $min, int $max);
mt_rand(int $min, int $max);
str_shuffle($str);
uniqid($prefix, more_entropy=);
?>

The two functions rand() and mt_rand() are likely the most widely used functions to generate a set of random numbers in PHP. The function rand(); is an older generator, and is falling out of use due to mt_rand(); which is faster, more reliable, and can handle a higher maximum integer value on some platforms. The function str_shuffle() does exactly what you would expect it to, it shuffles a string passed to it.

<?php
//Examples of mt_rand() usage
print mt_rand();//default
	
		echo "<br />";
	
print mt_rand(0, 20);//Outputs a random integer between 0 and 20
	
		echo "<br />";
	
//Examples of rand() usage
	
print rand();//default
	
		echo "<br />";
	
print rand(0, 25);//Outputs a random integer between 0 and 25

		echo "<br />";
	
//Example of str_shuffle usage
	
$string = 'abcefghijklmnopqrstuvwxyz';
	
print str_shuffle($string);//shuffles $string
?>

The rand() and mt_rand() functions both accept two parameters where $min is the lowest integer to start with, and $max being the largest integer to end with. The function str_shuffle takes one parameter, a string, outputting a shuffled mutation of the string. It acts the same as if you were shuffling a deck of cards.

While mt_rand(); will spit out a random integer, and str_shuffle will mix a string up, a function widely used to create random unique values is uniqid(). This generates a prefixed unique identifier based on the current time in microseconds(via php.net). Using this function is useful for creating session tokens and even form keys as seen in Secure Your Forms with Form Keys.

<?php
//Examples of uniqid() usage
	
print uniqid();//default
	
		echo "<br />";
	
print uniqid("NETTUTS", TRUE);//Adding an additional prefix and setting more_entropy to TRUE
?>

The function uniqid() accepts two parameters the first appends a prefix to the results while the second, if set to TRUE, will add additional entropy to the end of the returned value.


Generating Random Passwords

There are a gazillion examples on the web which generate random passwords, all do a fine job at it. "But why," you ask "would I need to generate a random password?" Well the answer, quite simply, is so you do not have to rely on the end user to provide themselves with a less than secure password at the get go. Generating random passwords is very useful in user registrations, or when a user makes a request because they have forgotten their password. Doing this ensures a strong password at the beginning of a users experience at your website, or can cut down lines of code when a user needs to gain access again.

Let's look at some examples:Example 1

<?php

//A simple function which will output a random password
function randompassword($count){

$pass = str_shuffle('abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@#%$*');

return substr($pass,3,$count);//returns the password

}
?>

This example shuffles a string with str_shuffle and will return a string within a counted range. So if you wanted to generate an 8 character password then you would pass 8 to the function randompassword, or randompassword(8) from your source code.

Example 2

<?php

//Another example to create a random password
function anorandpass($count) {
	
	$m_rand = mt_rand(); //generate a random integer

	$u_id = uniqid("MNO!@#$%^&*=+XYZ", TRUE);//create a unique identifier with some extra prefix and extra entropy
	
	$combine = $m_rand . $u_id;// Combine the variables to form a string
	
	$new = str_shuffle($combine);//shuffle our string
			
	return substr($new, 2, $count);//return the password
}
	
print anorandpass(8);

?>

In comparison, example one takes a static string and mixes it up then returns it, example two adds in more dynamic flavor(mmm tasty). In example two the string being shuffled is no longer static, but changes with each generation. While the first example is certainly sufficient in most cases to generate a strong password, the second example allows us to ensure the string length and characters will change with use, greatly decreasing the chance of a duplication.

Enforcing the use of strong passwords within a web application will deter users from visiting or signing up for a website. It is often a trade off between getting the traffic you desire, and ensuring the security of the application. I suggest allowing your users to create their own passwords at sign-up, or allow them to choose between the two.


Please Pass the Salt. Salting Passwords for Increased Security.

Salting passwords is an effective way to increase the security of your users accounts even if an attacker gains access to your database, if done right. It can be argued that, with access to the salt, an attacker can still gain your credentials. While this is true, applying some randomization techniques to the storage of passwords will make that process extremely difficult, especially if the storage of user information and content are divided into separate databases.


Why and How?

Again this falls under the "non-reliance of the end-user to provide themselves simple security" measure. Users generally use passwords which are easy to remember, and even use the same passwords across multiple websites(I know, right!?). Easy to remember passwords are generally words found in a dictionary and other kinds of values(ex. 12345, QWERTY). As developers we often scoff at this practice, but we cannot deny that it's just the way things are.

In order for a web application to utilize a salt in a password, the application has to store it somewhere. It's not recommended to use the same salt across an entire database of passwords, but to generate a unique salt per user. Generating one salt for an entire database actually decreases the security of the web application in a sense that if an attacker manages to crack it the entire scheme is broke, or if lost, renders the database useless. Creating a full fledged member registration system with all the bells and whistles is out of the scope of this tutorial, however we will be creating a simple system to use an example. Let's look at generating a salt and applying some randomization techniques:


1. The Database Connection

Here is the SQL table that we will be using.

CREATE TABLE IF NOT EXISTS `users` (
  `usr_id` int(11) NOT NULL AUTO_INCREMENT,
  `usr_name` varchar(24) NOT NULL,
  `usr_pass` varchar(32) NOT NULL,
  `usr_email` varchar(255) NOT NULL,
  `usr_salt` varchar(255) NOT NULL,
  PRIMARY KEY (`usr_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;
<?php
/*db_config.php*/

//database configuration
$db_host ="localhost" ; //will likely stay the same
$db_name = "thedbname"; //the name of the database table
$db_usr = "username"; //your database username
$db_pass = "password";//your database password

//Establish a connection with MySQL and select the database to use
mysql_connect($db_host, $db_usr, $db_pass) or die("MySQL Error: " . mysql_error());
mysql_select_db($db_name) or die("MySQL Error: " . mysql_error());
?>

2. The Registration File

<?php
/*registration.php*/

//require our db_config.php file
require ('db_config.php');

//Check to see if the form has been submitted
if(!empty($_POST['username'])  && !empty($_POST['email']) && !empty($_POST['password'])) {
	
    //Escape our posted inputs
	$username = mysql_real_escape_string($_POST['username']);
	$email = mysql_real_escape_string($_POST['email']);
	$password = mysql_real_escape_string($_POST['password']);
	
    //generate a strong unique salt
	$salt_gen = uniqid(mt_rand());
	
    //Combine email, the password and the salt together
	$combine = $email . $password . $salt_gen;
	
    //md5 hash the combined password * Note: md5 is only used in this scenario as an example
	$newpassword = md5($combine);
	
    //insert the values into the database
	$registerquery = mysql_query("INSERT INTO users (usr_name, usr_pass, usr_email,  usr_salt) VALUES ('".$username."', '".$newpassword."', '".$email."', '".$salt_gen."')") or die("MySQL Error: ".mysql_error());
	
    //let the user know of success or failure
	if ($registerquery) {
		echo '<h1>Success</h1>';
	} else {
		echo '<h1>Failure</h1>';
	}
}
?>

Let's go over the PHP code. To keep things simple we include our database config file. Next PHP checks to see if the form HTML has been submitted by checking if the $_POST variables are not empty. If they are not empty then the script proceeds to escape the posted form data from the user, preparing it to be inserted into the database. We then generate a simple salt using uniqid() and mt_rand() and storing it in the variable $salt_gen. To salt our password we combine the $password, then the salt. Next step, one way hashing the combined variables with md5.

"But wait! You also added the users email to the front of the password and salt combo!" Yup! I did this because, if an attacker gains access to my database in some way, and the salt, the only way the attacker is going to know for sure that the email address is used in the hashing of the password is if they have access to the source code. How random and unique is an email address?

To top the rest of the PHP code off we insert our variables into the database table within their respective fields, and give the user some feedback on success or failure. Now onto the rest of the registration file, the HTML

<!DOCTYPE html>
<html>

<head>

</head>

<body>

<form action="" method="post">
	<label for="username">Enter a Username</label>
    <input type="text" name="username" /><br />
    
    <label for="email">Enter your Email</label>
    <input type="text" name="email" /><br />
    
    <label for="password">Enter a Password</label>
    <input type="password" name="password" /><br />
    
    <input type="submit" name="submit" value="Submit" />
</form>

</body>

</html>

Here we create a simple HTML form which will collect a username, an email, and a password from a user. Nothing fancy here.


3. Authenticating the User

So we now have a simple registration form, which inserts a user into the database along with their salted password. Let's create a login page which will require us to retrieve information from the database and authenticate the user. First the PHP:

<?php
/*login.php*/

//require our db_config.php file
require ('db_config.php');

//Check to see if the form has been submitted
if(!empty($_POST['username'])  && !empty($_POST['password'])) {
	
	//Escape our posted inputs 
	$username = mysql_real_escape_string($_POST['username']);		
	$password = mysql_real_escape_string($_POST['password']);
	
	//Grab the row associated with the username from the form
	$grab_row = mysql_query("SELECT * FROM users WHERE usr_name = '".$username."'") or die ("MySQL Error: ".mysql_error());
	
	//If only one row was retrieved
	if (mysql_num_rows($grab_row) == 1) {
		
		//create an array from the row fields
		$row = mysql_fetch_array($grab_row);
		
		//store the users salt in a var
		$salt = $row['usr_salt'];
		
		//store the users email in a var
		$email = $row['usr_email'];
		
		//recombine the variables email, password, and the salt
		$combine = $email . $password . $salt;
		
		//re-hash the combined variables Note:md5 is only used in this scenario as an example
		$auth_pass = md5($combine);
		
		//check the database again for the row associated with the username and the rehashed password
		$checklogin = mysql_query("SELECT * FROM users WHERE usr_name = '".$username."' AND usr_pass = '".$auth_pass."'") or die("MySQL Error: ".mysql_error());
		
		//if only one row is retrieved output success or failure to the user
		if(mysql_num_rows($checklogin) == 1) {
			echo '<h1>Yippie, we are authenticated!</h1>';
		} else {
			echo '<h1>Oh no, we are not authenticated!</h1>';
		}
	} else {
		echo '<h1>Oh no, we are not in the database!</h1>';
	}
}
?>

Basically what we are doing in the login.php file is taking the submitted form variables, grabbing the table row associated with the username and rebuilding the password from the elements in the database it was created with (email, pass, salt) and rehashing them. We then check the database again for the username AND the rehashed password value to find a match, outputting the user on success or failure. Finally here is the HTML:

<!DOCTYPE html>
<html>
<head>

</head>

<body>
<form action="" method="post">
	<label for="username">Enter your Username</label>
    <input type="text" name="username" /><br />
     
    <label for="password">Enter a Password<label>
    <input type="password" name="password" /><br />
    
    <input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Obfuscation in PHP

A simple yet complex definition of obfuscation is (use the version contained in the source if you wish to run the code):

<?php $a1c0_z2='c'.$a91.'tion ';$a91="a";$vly_ti="us".'ed';$j1h_32_a=' to';$z1b_1=$a91." ";$lz32i_4="“O"."bfus";$g1k0p='que ';$lv83="t".'ec'.'hni';$lFa='i'.'s ';if($z1b_1==$a91." ")$rx_b_1='a';$glccUv=" complic".$rx_b_1.'te ';$xl1ttf='code ';$zljal1="in such a";if($z1b_1==$a91." ")$s1b_1='a';$p1x2 =" w".$s1b_1."y ";$il_7x=' '.$b1zE_.'t i'.$l1yes;$b1zE_="i";$l1yes="s";$nltotry_ws='st'.$s1b_1."n";$yl5B_='thαt ';$dlno=' not ';$m1tomanythings="under";if($s1b_1=='a')$bz_1=$s1b_1;$Ozaq="d".$bz_1."ble"";echo base64_decode("JiM4MjIwO09iZnVzY3Rpb24mIzgyMDE7aXMmIzgyMDE7YSYjODIwMTt0ZWNobmlxdWUmIzgyMDE7dXNlZCYjODIwMTt0byYjODIwMWNvbXBsaWNhdGUmIzgyMDE7Y29kZSYjODIwMTtpbiYjODIwMTtzdWNoJiM4MjAxO2EmIzgyMDE7d2F5JiM4MjAxO3RoJmFscGhhO3QmIzgyMDE7aSYjODIwMTt0JiM4MjAxO2kmIzgyMDE7bm90JiM4MjAxO3VuZGVyc3RhbmRhYmxlJnF1b3Q7");?>

As you can see, this code is not meant to be distinguishable. There are no distinct variable names, there are no comments, no spacing, no indentation, no distinct order and it's all in one line. Even though we cannot distinquish the code, our machines still know what it is. It works. This one line of chaos simply echos "Obfusction is a technique used to complicate code in such a way that i t i not understandable." Yes, I know about the errors.

Obfuscation has pros and cons. It's purpose is to disuade a person from finding out what code is doing at a glance, or for a period of time. This is a plus toward individuals with little to no knowledge of the programming language. However, anybody who has a basic understanding of PHP can disseminate the above obfuscated code and figure out what it's doing, it might just take a little time. This is one of the flaws of obfuscation, it is not a form of encryption, it's just an attempt to be cryptic. Obfuscation also normally adds to filesize. A lot of the time, you'll encounter obfuscated code in propriatary and malicious software.


So How Can I Obfuscate My Code?

This is a common question. There are primarily two ways to obfuscate your code. First, you can do it by hand. Writing obfuscated code takes a long time. The example used in this article took a while to write because of the same reasons you use obfuscation in the first place (lack of structure, order etc...), this even resulted in some menial errors which I didn't even want to hunt down and fix. The second way you can obfuscate your code is by buying software that does it for you. Using a program to obfuscate code is trivial, and of course costs money a lot of the time. Some software which claims to obfuscate your code, actually encrypts and/or encodes it in such a way it relies on a handshake to function. Often you'll find software whose vendor won't even guarantee your code will work when it's done. Even in the example, I used a simple Base64 function to encode the construction of the script output.


Some Obfuscation Tips

  • Always, always, keep a clean version of the source for yourself.
  • The more random your technique, the better.
  • Eliminate all whitespace, where it is not needed.
  • Character Encode printed/echo'ed characters and spaces (i.e. quotations, thin spaces, apostropes, hypens)
  • The more complex the code, the better.
  • Disregard structure unless it is detrimental to the operation of the code(e.x. variable locations before they're called)
  • Do not use distinguishable variable names, namespaces, or class names.
  • The less code you reuse, the better
  • Don't believe it's foolproof

To Obfuscate or Not to Obfuscate?

It really depends on your plan. Particularly if your looking to sell your PHP script (or any software) you need to license it. This is going to be one of the front line defenses to thwart the softwares intended audience from doing whatever they want. A prime example of licensing can be seen in the Envato Marketplace Wiki. However, you may want to obfuscate some, or all of your code for whatever reason. However due to obfuscations negatives, if your really that worried about the security of your source code, it may be worth looking to encryption instead.


Cryptography in PHP

Wikipedia.com defines cryptography as:

"the practice and study of hiding information."

Cryptography is a big deal, wether your aware of it or not. In almost every web application presently deployed there is some presence of cryptography being utilized (i.e. mail clients and websites). As developers we need to be informed and aware of the practical applications of cryptography within our software. PHP provides us with some very fundamental and practical functions we can utilize to encrypt data. In this section, I will be mainly going over one-way hashing algorithms though I will touch lightly on Symmetric-key based encryption. There are plenty more (i.e. Steganography, Asymmetric-Key to name a couple).


The One Way Hash

Alot of the time we utilize one-way hashing as a way to securely store passwords and check the data integrity of files. While we do this, to authenticate members of a web application we hash the users entered password, and match it against the users stored hash. The same technique applies to checking the integrity of files.

SHA-1, 2, and 3

The SHA family of hash algorithms are currently the most popular, significantly SHA-1. Even though the SHA-1 algorithm may have a weakness, it is still in wide use.

<?php

///One way hashing with SHA-1

$string = "Netuts is Awesome";

$hash = sha1($string);
//or
$hash2 = hash('sha1', $string);

echo $hash."<br />";
echo $hash2."<br /><br />";

//Will output: 42d2f15c3f92d28d7d58776e5d81b800f662cc6c 
?>

In PHP, SHA-2 is called upon in a different respect, and requires PHP 5 greater than or equal to 5.1.2. SHA-2 is superior to SHA-1 and can be called with different bit sizes.

<?php
$string_sha256 = "Nettuts is Awesome";
$string_sha384 = "Nettuts is Awesome";
$string_sha512 = "Nettuts is Awesome";

$hash_sha256 = hash('sha256', $string_sha256);
$hash_sha384 = hash('sha384', $string_sha384);
$hash_sha512 = hash('sha512', $string_sha512);

echo $hash_sha256."<br />";
echo $hash_sha384."<br />";
echo $hash_sha512."<br />";

/* Outputs repspectively:
sha256 : 09074adc0d70e15b88494643e29c2836e1ab94a21989691dec594cb0bd742ebc
sha384 : 8535470750df54a78701d4bfe0451f9799057a5bc101944a32480d2436e8b95440bce3bcab3f9ce107b0b92d9595ae32
sha512 : c2e6dce873a71800b862791e56b480b976bb26cd3136c02da510c3905caa49b7b9e9260549976e1e741cc93e4569a611f2030d3b7104c6c6c2ff9e6c9bf0946a
*/

?>

The hash function is called by hash(algorithm, string); In the newest PHP versions the hash() function can be used to call any one-way hash algorithm PHP supports (i.e. md5, sha-1, haval, ghost). If you want to see a list of all the registered hashing algorithms you can use:

<?php
//As of PHP5 >= 5.1.2
print_r(hash_algos());
?>

SHA-3 is still being developed and considered for standardization. A competition to find a good candidate to act as the new secure hash algorithm was launched by the National Institute of Standards and Technology and entries for the competition were deadlined for October 31, 2008. A rather popular entry named Skein, has an available PHP module you can download (though you have to compile it yourself). Skein is developed by some big names found within the security industry such as Bruce Schneier, Niels Ferguson, and Stefan Lucks to name a few. The official Skein website can be found here.


Key-based Encryption

Symmetric-Key encryption methods is where the security of the encryption primarily resides within a key, which is shared between two points, where the data is encrypted and where the data is decrypted. A very good example of how this can work was provided by Christian Beikov's "Creating a Crypter Class with PHP" tutorial.


HMAC

Essentially HMAC is like a mix between one-way hashing and key based encryption. HMAC security relies on the key size used, and strength of the hash function it is calculated with. You can somewhat compare this method to salting passwords.

<?php
$string_hmac = "Nettuts is Awesome";

//hash_hmac(algorithm, string to hash, key)
$hmac = hash_hmac('sha1', $string_hmac, 'secret');

echo $hmac."<br />";
?>

Wrapping it All Up

Well what a journey! Randomizing values, generating random passwords, salting, storing and authenticating users, obfuscation, crypto...seems like alot to take in. But worth it! It's important to know what kind of security your going to implement into your web applications, and how your going to protect it. Even more, it's important to keep a clever attitude towards these implementations and not think that security is only implemented by a few methods, but by a combination of them, with a dash of creativity.

Advertisement