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. The str_shuffle function 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(). The function uniqid() 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.
- Follow us on Twitter, or subscribe to the Nettuts+ RSS Feed for more daily web development tuts and articles.
Related Posts
Check out some more great tutorials and articles that you might like
Plus Members
Source Files, Bonus Tutorials and
More for $9 a month for all TUTS+
sites in one subscription.
















User Comments
( ADD YOURS )Andrew Chalkley October 2nd
My pro tip:
You could secure a website by taking it off the internet.
( )Faifas October 5th
I couldn’t offer a better solution.
( )Hayden October 21st
That would also defeat the purpose of having a web site.
The correct way to say that and the purpose in it is to say “The only absolute way to secure a server is to unplug it”. The purpose being that no matter what safeguards you put in place it will always be vulnerable to attack.
( )Michael October 2nd
Great post! It’s always good to remember the security. Thanks!
( )Michael October 2nd
Is it too late to show what the encrypted values look like in the tut? i.e., the value that the HMAC hash ends up looking like? I think that would be pretty neat to see as well. If not, no big deal.
( )Diego SA October 2nd
That’s awesome! A simple thing that could bring a safer system than a lot out there. Awesome tutorial. Thanks a lot!
( )Dustin Blake October 2nd
Glad you like the tut! Your welcome.
( )Nick October 2nd
Is it wise to store the salt in the database, right next to the salted password? Doesn’t that kind of defeat the purpose of salting a password?
( )Mark October 14th
I would suggest two types of “salt” a unique one stored in the database and a common one stored in a PHP configuration file (not stored in the shared web root). The stored salt helps to prevent password brute forcing/dictionary attacks and the configuration salt will help to prevent access to your web application if the database/user table is compromised (say through sql injections), but not the file system.
So when creating the password hash you would do something along the lines of this:
$hash = hash_alg($CONFIG_SALT.$pwd.$salt_gen);
Personally I do something like this:
$hash = hast_alg(hash_alg($CONFIG_SALT.$pwd.$email).$salt_gen);
Double hashing helps to make sure that the hash cannot be brute forced or guessed. It would take much much longer for a dictionary attacker to guess that hash 4er87f4d535fdf5331d389d7d32b1801f20d2e6 is a hash of d9b36e6b08845331d38937cd7d32b1801f20d2e6 rather than a hash of say “mysalt.dog.dog@gmail.com.2345″ when they are able to retrieve 2/4 of those values from the database. This is kind of overkill, but when it comes to security nothing is guaranteed so you must secure things in depth and in breathe.
( )Dustin October 2nd
The HMAC output looks like :
d9b36e6b08845331d38937cd7d32b1801f20d2e6
( )Montana Flynn October 2nd
As a PHP beginner I enjoyed your post very much.
( )Arvi October 3rd
Same here. Thanks Dustin. Great Tut!
( )Dustin October 5th
Your welcome Arvi, I’m glad you found it useful.l
IgnacioRV October 2nd
You know? Tomorow I have a an information security exam at university…
Thanks for the article, now I know how to implement some of the theory I’ve read about
About SHA-1, the problem is that with today’s computing resources it’s not very resistant to collisions (it isn’t very difficult to get two pieces of text with the same result), but for small projects there should be no problems , of course it depends on what you will be encrypting… don’t use it for credit cards numbers or bank accounts passwords =P
( )Dustin Blake October 2nd
exactly, any system which handles highly sensitive information should always use the highest possible standard of encryption
( )Lam Nguyen October 2nd
Great post! I always look for security solutions in PHP. Thanks
( )Dave McFarland October 2nd
why are you using mysql extension (mysql_connect for example) instead of mysqli (mysqli_connect)?
( )Callum October 2nd
Does it really matter? It makes no difference to how the code executes.
( )Dustin Blake October 2nd
If the example were to be used in a live deployment to handle users, mysqli would be preferred. Using the regular mysql extension instead of mysqli is basically for backwards compatibility for older database’s. I certainly hope nobody is still using pre mysql 4.1, but I didn’t want to make that assumption in my example.
I also used the insecure md5 hashing function in the salting example, but did not talk about it in the Cryptography section.
At this point msql and mysqli are still a manner of preference, personally I use mysqli but still find myself using the older method from time to time.
Erik October 2nd
Well, The guys at MySQL clearly state that people should start using MySQLi – MySQL(improved).
However, you’re correct – no real big importance. I think it’ll be considered a best practice thing in the future.
Jeffery Way uses it. I use it >< —- Thats the motto I use these days.
( )KA October 2nd
Thanks for the awesome tutorial again!
( )Dustin Blake October 2nd
Your welcome!
( )Yigit Ozdamar October 2nd
Great post! Safety first!!! lol
( )Ryan October 2nd
Awesome tutorial – so detailed too. Thanks
( )Jaspal Singh October 2nd
Great Tutorial, best of security lessons for php developers.
( )Thanks for sharing.
Dustin Blake October 2nd
Your welcome, always glad to share
( )blues October 2nd
Great tutorial indeed. It’s gonna be very helpful in my next work.
( )Roger October 2nd
Some good stuff here. Thanks.
( )Lamin Barrow October 2nd
Nice post. Thanks for the code snippets.
( )Robert October 3rd
The password salting techniques are not ideal, at all. The biggest issue is with MD5 itself- this is a fairly common mistake, mostly because it keeps getting perpetuated. MD5 was designed with speed in mind, and in this case thats a bad thing. If you use a hash that takes twice as long to run its going to take hackers twice as long to generate rainbow tables against it.
The ideal hash method would be to use bcrypt, which is supported natively in php 5.3 and through extensions in earlier versions. If thats not available you can use something like whirlpool and just loop it through a hundred times. Or, perhaps even better, you can use one of the many password libraries put together by experts.
For reference, you’re in good company on this mistake. Jeff Atwood, of CodeHorror fame, wrote an article about passwords which prompted Thomas Ptacek to write this fantastic article about it-
http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
( )Dustin Blake October 3rd
As I wrote:
//md5 hash the combined password * Note: md5 is only used in this scenario as an example
And right. md5 is fail, that’s why I didn’t even make mention of it in when I discuss hashing. Ptacek is absolutely correct about slowing down the hashing function and why.
A salt can be applied into a hash in a variety of ways, it’s not limited to being appended before or after the password.
The argument for ‘whats best’ or ‘ideal’ can go on forever, and if you ask me it’s not whats important. Whats important is ‘whats good’ and its application within development.
( )Web 2.0 Tools October 3rd
Useful tutorials, thanks…
( )Simon October 3rd
Thanks for the nice tutorial. I didn’t know about the hash() syntax.
( )I’m always wondering, what about performance ? Is sha1 slower than md5 ? What about sha1 vs sha2 ? Is the mcrypt function stressful ? If someone knows some good articles about these points I would appreciate it !
Thanks again
Simon October 3rd
Ok just found it myself xD
( )Not the best benchmark ever but at least you get the idea:
http://de3.php.net/manual/en/function.hash.php#89574
Ben October 3rd
Really good post, thanks!
I’ll definitely be putting some of these examples into practice. And i finally know what salting is
( )Dustin Blake October 3rd
I’m glad you found the info useful.
( )Julius Beckmann October 3rd
I wrote a class for secure password hashes. Take a look at it:
( )http://juliusbeckmann.de/blog/easy-to-use-and-secure-php-hashing-class.html
It uses random salts, iterations and permutations and you can create own hashing methods.
Hour October 3rd
it’s = it is
( )Chris October 3rd
This tutorial is awesome! Easy explanation and deployment of security mechanism in PHP every web developer should know about!
( )Fábio Antunes October 3rd
Hi.
Awesome tut, really good.
I was “ahhhhh” when i rote “print_r(hash_algos());” and have run it.
You could post something about some of those more unfamiliar “hashing” algorithms, that we can in PHP and others.
PS: You should also mentioned not to keep connection details (your “db_config.php”) inside the public_html / htdocs / www folder.
Any way. Very Good.
( )Thanks.
Dale October 3rd
Just wondering if it you could generate salt using an algorithm?
Say:
1. Get all of the ASCII values of the password
2. Sum up the values
3. Times the sum values by the amount of letters
4. Plus each of the digits in the returned results together and keep doing so till you get a number between 1 and 9
5. Have 9 salt values and use the one corresponding salt
6. Use MD5 or other for the password and salt
Dale
( )Lisa October 4th
I already had a basic understanding of most of these techniques but now I understand them even better. This is the best article I’ve read on the topic, clear and informative. Thanks!
( )Andrew October 5th
I’m just taking a beginners php/mysql class now, and this was fan-fing-tastic. I seriously just finished the first 3 chapters in my book, then came across this… it was completely comprehensible. I think that says a lot about how well written of an article it was.
It would be interesting to “zoom out” and talk about the theory behind all this… like how taking these steps will make your site/app more secure based off what the attacker is likely to do and what tools he/she has. I kind of assume that a lot of people here already know that side, but for a beginner it would be very useful to understand the logic.
Anyway… enough rambling… seriously great article.
( )Kevin Quillen October 5th
Code obfuscation by hand? Thats insanity.
( )Dustin October 5th
lol, I know right!
I wrote my example all up and seen there were some typo’s and I didn’t even want to go and fix them…
( )Kevin Quillen October 5th
http://www.raizlabs.com/software/phpobfuscator/
http://phplockit.com/
http://www.zend.com/en/products/guard/
etc
joel October 5th
a mislabeled article, as it was more a generic discussion of general php hashing techniques, and really NOTHING to do with “locking down a website”.
As such, it falls into the common IT flaw of taking ONE issue, and tossing an inordinate amount of resources and time on it without looking at not only the big picture, but the real picture.
The entire premise of the article (as posited in the context of ‘locking down a site’) is wrong, as it is primarily about ENFORCING THE SECURITY OF ALREADY STOLEN DATA. A *real* article about ‘locking down’ a site, would look at some of the common, obvious, and some out of the box ways that websites are compromised.
For instance, most websites are hacked due to..
1. Exploited opensource platforms i.e. WordPress, Joomla, SMF forum which all are very popular and to this day have exploitable weakness.
2. Poorly vetted code. Many of these ‘tut’ sites are to blame, tossing around ‘login’ code, ‘admin code’ which are very general, very basic, but are snapped up by newbies and somehow become ‘best practices’. As secure as your ’salting’ of the Passwords and all the hashing that you do, if your site takes user content (like this one) and does not sanitize the inputs properly, then the site could be compromised and silently too, with a javascript key logger recording your key strokes (how’s that ’salt’ working for ya?)
3. Social engineering and guessing poorly chosen passwords.
4. Cross site scripting (where people can take actions without even using the password)
5. Ajax hacking. This is really the ‘poor code’ mentioned earlier, but I say it here again, as you see it in sites that are otherwise quite robust, but have some ridiculously flawed ajax routines that are the weak link to penetrate and compromise the site.
6. Phishing. where a cloned copy of your site’s admin panel is presented with the hope you try to login to it.
there’s more of course -maybe if you were gonna write a REAL article you might do some research
( )Dustin October 5th
Did you even read it?
Nowhere in the article did I state “Hey these techniques are going to keep your website hacker-proof”, that would just be…dumb. Of course you provided excellent examples of attack methods, where are your examples of defending against such attacks?
Your only argument is what the article lacked. Which I could see as a viable argument if I would have said ‘hey this is what your going to learn’, but I didn’t, in the introduction I specify what the article will be going over.
If your so unhappy with what tutorial sites publish then why don’t you enlighten us with your own?
( )Pedro Henrique October 6th
Don´t bother man, he just had a bad day.
Easy is to criticize, hard is to make it done.
Maybe we´ll see some good information from ‘joel’ in the next weeks. Maybe not.
Rick October 6th
Your right Dustin!
Joel; if you know so much, and better, then please improve the online community by publishing your own tutorials. For example; instead of only mentioning your point 6, tell me, how can I prevent myself from it? Ow, and this time write a REAL comment
The only thing I was thinking of, regarding the encryption of the scripts, is indeed ZendGuard (www.zend.com, mentioned above in comments) or Ioncube (www.ioncube.com). I have recently tested a php application for my work, in order to determen if it adds value to the business. This application was encoded with ZendGuard. As far as I have tried, there is just no f*cking way to do anything in that code. It was completely locked.
This might be of great value when you want to sell an application on license base. You encrypt the licensing part and leave the rest open to give your costumer full control. Don’t ask me how it exactly can be done, but I’ve seen applications around which use this technique. (like http://www.kayako.com)
Kevin Jensen November 11th
I want to see this tutorial on how to stop phishing. That will be a good one.
Daquan Wright October 6th
Even if the article has flaws, the concepts look to revolve around protecting your data and honestly anyone building a web app will have to research methods of data protection for their own respective projects (a tutorial can only do so much). Just than an article isn’t here to provide us with pretty code but instead remind us to never trust user input is a great thing.
Good article Dustin. He won’t be writing any articles to show off his knowledge most likely, words are cheap.
( )Myfacefriends October 6th
another useful and wonderful tuts… keep on shinning…. many thanks. awesome!
( )sharin_sg October 7th
this is a useful and helpful tutorials. thanks for sharing.
( )Steve October 7th
Seems that this isn’t really techniques to lock down your website but lock down your PHP passwords…… I thought this would be more of explanation of permissions and what can be done to help lock your site down from the title.
There are more commercial products like zend encoder and ioncube loader that can help lock your code. In particular you want to protect sensative files such as db.php since anyone can view the source (generally) when on shared hosting.
Also it’s good practice to protect your DB scripts in even of remote script execution exploit as well. No mention of XSS either… I should write an article
( )Stok October 8th
Hi, tnx for this,but not enough
( )Xaby October 9th
a really good post! though i dun really understand some of the quotes
( )Cosmin October 9th
Hi. Great tut on locking the php source code. I’ll study this more, this is interesting…
( )RedPyxll October 10th
Great tutorial, posted to my new tech blog at RedPyxll. http://bit.ly/4azPua
( )Thanks.
Imran Khan October 11th
Thanks nice post, ill have a deep look at it.
( )Joe October 11th
Pretty good security tips!
( )Bogdan Pop October 13th
Before securing your site, you’d better off securing your server. A super doooper secured site can be teared apart if the server running it has bad security configurations and blank root passwords.
( )dr.emi November 10th
hey! I want to know how to create encoded script like on “Obfuscation in PHP”
( )Karlos November 20th
You show your MySql errors to the public??????? Surely this is one of the first lines of defense in securing your database and website scripting. Im shocked.
mysql_connect($db_host, $db_usr, $db_pass) or die(“MySQL Error: ” . mysql_error());
You also use md5 in one of your scripts. This is now broken and no longer presumed industry standard.
And the below line is unecessary as you could just use the MySql respose to identify if theres a matched record.
( )if(mysql_num_rows($checklogin) == 1)
Dustin November 26th
Thanks for the response, I show my errors when I’m developing a website, or a script, up until I make it available to the public, unless you intend to copy and paste this for you own implementations, yea, your gonna show MySQL errors unless you fix it yourself.
Yes I used MD5 as an example, I know MD5 is broken, I assume you had no intention to read commented code.
( )Paul Chater January 22nd
I think that some people should really re-read and reiterate to themselves the title of this post, “SIMPLE” would be a key word. Haha.
I think now-a-days practically every coder knows that MD5 is indeed broke, and should use one of the SHA methods with salting. It’s interesting… Although I definitely wouldn’t recommend storing the string in the database. Heh that’s just askin’ for trouble in my eyes.
The way I encrypt is using an encryption key of a random string sha1-hashed, then hashing that hash again and using that hash as the salt and then hashing the actual users password with the salt appended. Personally I think it’s very secure haha, but I think I’d need a crypto-geek to tell me if it’s a highly secure way.
Kingdutch February 1st
I’m too lazy to read all the comments so I dunno if no one else posted it yet.
But am I the only one to notice in 3. Authenticating the user you actually only need a valid username? As your SQL never actually checks against the password? ^^
(You first use the username to get salt and e-mail and then match again just against the username)
( )