PHP
Raiting:
17

Secure password hashing and storage


Hello, UMumble! Once, I was faced with a choice in the process of developing an authentication system for my project. Namely, what is the best way to store user passwords in the database? Many options came into my head. The most obvious were:

1. Storing the passwords as a plain text in a database.
2. Using regular hashes, such as crc32, md5, and sha1.
3. Using crypt() function.
4. Using the statical salt as type of structure md5(md5($ pass)).
5. Using the unique salt for each user.

The first and second options I had to eliminate for several reasons right away.

Collision of the hash functions

The collision of the hash functions occur when it gives the same result for the different input data. Of course, its probability is sufficiently small, and it depends on the length of the hash. However, the old (but still used occasionally) function crc32() returns 32-bit integer as the hash. Namely, in order to fit the password to this hash, according to the probability theory needed to get 2^32 = 4,294,967,296 different hashes. Even on my free hosting crc32 is running about 350 000 times per second, so you do the math yourself how many seconds you need to crack this hash ;).

Of course, this does not have to do with md5() (128-bit hash) and all the more with sha1() (160-bit hash). Using their collision is practically impossible, although there is a short article ...

Rainbow tables

Rainbow tables are composed of the most commonly used hash passwords, such as the names, dates of birth, names of animals, etc. These tables could include millions, billions of values, but work with them is relatively quick, and to check the hash against the one of the values it is not that difficult. Often, you can shield yourself by using salt or structures such as md5(sha1(md5($ pass))).

$password = "easypassword"; // is the simplest password entered by the user, and probably it is available in a rainbow table
echo sha1($password); // hash of this password when using function sha1() will be as follows: 6c94d3b42518febd4ad747801d50a8972022f956
$salt = "f#@V)Hu^%Hgfds"; // using a random set of symbols, we can change the hash value
echo sha1($salt . $password); // here is the hash for a password with the salt: cd56a16759623378628c0d9336af69b74d9d71a5
// such combination of password and its hash will not be found in any rainbow table.

Rainbow tables. Part 2

The statical salt and other similar structures can serve quite well ... so far their structure and salt are kept in a secret. If an attacker exposes the secret of hashing, then he could easily modify his rainbow table. That means that we cannot completely rely on the protection system of our server, we need to find another option. One of the solutions may be generation of the unique salt for each user, something like this:

$hash = sha1($user_id . $password);
Even better it is just to generate the random salt, such as:

// generate the random string of 22 symbols
function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}

$unique_salt = unique_salt();
$hash = sha1($unique_salt . $password); // form the hash of the password

Of course, the unique salt should be entered into the database, but even having access to it, an attacker will not be able to generate millions of rainbow tables.

Hashing speed

It would seem that the faster hash will be generated, the sooner our user can login and begin to bring a profit. However, the faster is the speed of hashing the sooner attacker could crack it.

Modern PCs with powerful GPUs can generate millions of hashes per second, and more. And it allows breaking the passwords by a simple selection, using a brute force attack. Do you think that the password of 8 symbols is safe? If the password uses the symbols in the upper and lower registers and numbers, then the total number of possible symbols will make 62 (26+26+10). If the password has length of 8 symbols, there are 62^8 different combinations (it is about 218 trillion). At a speed of 1 billion hashes per second the password will be broken in about 60 hours. And the most common password with the length of 6 symbols will be cracked less than two minutes.

Of course, we can ignore the users, using short and simple passwords or make everyone to use 10-symbol passwords with the punctuation marks and symbols of the Sumerian cuneiform. But it is better to use a slow hash function. For example, the hash function can be slowed down manually in 1000 times using the following code:

function myhash($password, $unique_salt) {
$salt = "f#@V)Hu^%Hgfds";
$hash = sha1($unique_salt . $password);
// increasing the execution time of function in 1000 times, forcing first the function will be executed in 1000 times, and then to return back the result
for ($i = 0; $i < 1000; $i++) {
$hash = sha1($hash);
}
return $hash;
}

Using it, instead of 60 hours a hacker will be breaking the 8-symbol password about 7 years. A more convenient option for slowing it down is using the algorithm Blowfish, implemented in PHP over crypt(). To check if this algorithm is available, you can use if (CRYPT_BLOWFISH == 1) echo 'it works!'; In PHP 5.3 Blowfish is included.

function myhash($password, $unique_salt) {
// salt for blowfish must be 22 symbols in length
return crypt($password, '$2a$10$'.$unique_salt);
}

$2a – indicates the will be used Blowfish algorithm
$10 - it is a slowing down force of the function. In this case, it is equal to 2^10. It can take values from 04 to 31

Let’s use it in a particular example:

$hash = '$2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC';
$password = "verysecret";

if (check_password($hash, $password)) {
echo "Access granted";
} Else {
echo "Access denied";
}

function check_password($hash, $password) {
// the first 29 symbols of the hash, including algorithm, slowing down force and the original salt we place it in the variable $full_salt
$full_salt = substr($hash, 0, 29);
// execute a hash function for the variable
$password
$new_hash = crypt($password, $full_salt);
// return the result ("true" or "false")
return ($hash == $new_hash);

This code should provide the maximum security. It is almost impossible to fit the password of regular complexity and length using the software methods.
Pirat 4 may 2012, 20:45
Vote for this post
Bring it to the Main Page
 

Comments

0 ZachSmith July 4, 2013, 18:23
this was actually informative - not like most of what i see online. sharing :)
0 SteveFort September 16, 2013, 10:55
Hey Pirat, this is awesome post. This is the actual coding for password.. Seems good..

Leave a Reply

B
I
U
S
Help
Avaible tags
  • <b>...</b>highlighting important text on the page in bold
  • <i>..</i>highlighting important text on the page in italic
  • <u>...</u>allocated with tag <u> text shownas underlined
  • <s>...</s>allocated with tag <s> text shown as strikethrough
  • <sup>...</sup>, <sub>...</sub>text in the tag <sup> appears as a superscript, <sub> - subscript
  • <blockquote>...</blockquote>For  highlight citation, use the tag <blockquote>
  • <code lang="lang">...</code>highlighting the program code (supported by bash, cpp, cs, css, xml, html, java, javascript, lisp, lua, php, perl, python, ruby, sql, scala, text)
  • <a href="http://...">...</a>link, specify the desired Internet address in the href attribute
  • <img src="http://..." alt="text" />specify the full path of image in the src attribute