Understanding Hash Functions and Keeping Passwords Safe

Understanding Hash Functions and Keeping Passwords Safe

Tutorial Details
  • Language: PHP
  • Difficulty: Intermediate
  • Estimated Completion Time: 30min

From time to time, servers and databases are stolen or compromised. With this in mind, it is important to ensure that some crucial user data, such as passwords, can not be recovered. Today, we are going to learn the basics behind hashing and what it takes to protect passwords in your web applications.


1. Disclaimer

Cryptology is a sufficiently complicated subject, and I am by no means an expert. There is constant research happening in this area, in many universities and security agencies.

In this article, I will try to keep things as simple as possible, while presenting to you a reasonably secure method of storing passwords in a web application.


2. What Does “Hashing” Do?

Hashing converts a piece of data (either small or large), into a relatively short piece of data such as a string or an integer.

This is accomplished by using a one-way hash function. “One-way” means that it is very difficult (or practically impossible) to reverse it.

A common example of a hash function is md5(), which is quite popular in many different languages and systems.

$data = "Hello World";
$hash = md5($data);
echo $hash; // b10a8db164e0754105b7a99be72e3fe5

With md5(), the result will always be a 32 character long string. But, it contains only hexadecimal characters; technically it can also be represented as a 128-bit (16 byte) integer. You may md5() much longer strings and data, and you will still end up with a hash of this length. This fact alone might give you a hint as to why this is considered a “one-way” function.


3. Using a Hash Function for Storing Passwords

The usual process during a user registration:

  • User fills out registration form, including the password field.
  • The web script stores all of the information into a database.
  • However, the password is run through a hash function, before being stored.
  • The original version of the password has not been stored anywhere, so it is technically discarded.

And the login process:

  • User enters username (or e-mail) and password.
  • The script runs the password through the same hashing function.
  • The script finds the user record from the database, and reads the stored hashed password.
  • Both of these values are compared, and the access is granted if they match.

Once we decide on a decent method for hashing the password, we are going to implement this process later in this article.

Note that the original password has never been stored anywhere. If the database is stolen, the user logins can not be compromised, right? Well, the answer is “it depends.” Let’s look at some potential problems.


4. Problem #1: Hash Collision

A hash “collision” occurs when two different data inputs generate the same resulting hash. The likelihood of this happening depends on which function you use.

How can this be exploited?

As an example, I have seen some older scripts which used crc32() to hash passwords. This function generates a 32-bit integer as the result. This means there are only 2^32 (i.e. 4,294,967,296) possible outcomes.

Let’s hash a password:

echo crc32('supersecretpassword');
// outputs: 323322056

Now, let’s assume the role of a person who has stolen a database, and has the hash value. We may not be able to convert 323322056 into ‘supersecretpassword’, however, we can figure out another password that will convert to the same hash value, with a simple script:

set_time_limit(0);
$i = 0;
while (true) {

	if (crc32(base64_encode($i)) == 323322056) {
		echo base64_encode($i);
		exit;
	}

	$i++;
}

This may run for a while, though, eventually, it should return a string. We can use this returned string — instead of ‘supersecretpassword’ — and it will allow us to successfully login into that person’s account.

For example, after running this exact script for a few moments on my computer, I was given ‘MTIxMjY5MTAwNg==‘. Let’s test it out:

echo crc32('supersecretpassword');
// outputs: 323322056

echo crc32('MTIxMjY5MTAwNg==');
// outputs: 323322056

How can this be prevented?

Nowadays, a powerful home PC can be used to run a hash function almost a billion times per second. So we need a hash function that has a very big range.

For example, md5() might be suitable, as it generates 128-bit hashes. This translates into 340,282,366,920,938,463,463,374,607,431,768,211,456 possible outcomes. It is impossible to run through so many iterations to find collisions. However some people have still found ways to do this (see here).

Sha1

Sha1() is a better alternative, and it generates an even longer 160-bit hash value.


5. Problem #2: Rainbow Tables

Even if we fix the collision issue, we’re still not safe yet.

A rainbow table is built by calculating the hash values of commonly used words and their combinations.

These tables can have as many as millions or even billions of rows.

For example, you can go through a dictionary, and generate hash values for every word. You can also start combining words together, and generate hashes for those too. That is not all; you can even start adding digits before/after/between words, and store them in the table as well.

Considering how cheap storage is nowadays, gigantic Rainbow Tables can be produced and used.

How can this be exploited?

Let’s imagine that a large database is stolen, along with 10 million password hashes. It is fairly easy to search the rainbow table for each of them. Not all of them will be found, certainly, but, nonetheless…some of them will!

How can this be prevented?

We can try adding a “salt”. Here is an example:

$password = "easypassword";

// this may be found in a rainbow table
// because the password contains 2 common words
echo sha1($password); // 6c94d3b42518febd4ad747801d50a8972022f956

// use bunch of random characters, and it can be longer than this
$salt = "f#@V)Hu^%Hgfds";

// this will NOT be found in any pre-built rainbow table
echo sha1($salt . $password); // cd56a16759623378628c0d9336af69b74d9d71a5

What we basically do is concatenate the “salt” string with the passwords before hashing them. The resulting string obviously will not be on any pre-built rainbow table. But, we’re still not safe just yet!


6. Problem #3: Rainbow Tables (again)

Remember that a Rainbow Table may be created from scratch, after the database has been stolen.

How can this be exploited?

Even if a salt was used, this may have been stolen along with the database. All they have to do is generate a new Rainbow Table from scratch, but this time they concatenate the salt to every word that they are putting in the table.

For example, in a generic Rainbow Table, “easypassword” may exist. But in this new Rainbow Table, they have “f#@V)Hu^%Hgfdseasypassword” as well. When they run all of the 10 million stolen salted hashes against this table, they will again be able to find some matches.

How can this be prevented?

We can use a “unique salt” instead, which changes for each user.

A candidate for this kind of salt is the user’s id value from the database:

$hash = sha1($user_id . $password);

This is assuming that a user’s id number never changes, which is typically the case.

We may also generate a random string for each user and use that as the unique salt. But we would need to ensure that we store that in the user record somewhere.

// generates a 22 character long random string
function unique_salt() {

	return substr(sha1(mt_rand()),0,22);
}

$unique_salt = unique_salt();

$hash = sha1($unique_salt . $password);

// and save the $unique_salt with the user record
// ...

This method protects us against Rainbow Tables, because now every single password has been salted with a different value. The attacker would have to generate 10 million separate Rainbow Tables, which would be completely impractical.


7. Problem #4: Hash Speed

Most hashing functions have been designed with speed in mind, because they are often used to calculate checksum values for large data sets and files, to check for data integrity.

How can this be exploited?

As I mentioned before, a modern PC with powerful GPU’s (yes, video cards) can be programmed to calculate roughly a billion hashes per second. This way, they can use a brute force attack to try every single possible password.

You may think that requiring a minimum 8 character long password might keep it safe from a brute force attack, but let’s determine if that is, indeed, the case:

  • If the password can contain lowercase, uppercase letters and number, that is 62 (26+26+10) possible characters.
  • An 8 character long string has 62^8 possible versions. That is a little over 218 trillion.
  • At a rate of 1 billion hashes per second, that can be solved in about 60 hours.

And for 6 character long passwords, which is also quite common, it would take under 1 minute.

Feel free to require 9 or 10 character long passwords, however you might start annoying some of your users.

How can this be prevented?

Use a slower hash function.

Imagine that you use a hash function that can only run 1 million times per second on the same hardware, instead of 1 billion times per second. It would then take the attacker 1000 times longer to brute force a hash. 60 hours would turn into nearly 7 years!

One way to do that would be to implement it yourself:

function myhash($password, $unique_salt) {

	$salt = "f#@V)Hu^%Hgfds";
	$hash = sha1($unique_salt . $password);

	// make it take 1000 times longer
	for ($i = 0; $i < 1000; $i++) {
		$hash = sha1($hash);
	}

	return $hash;
}

Or you may use an algorithm that supports a "cost parameter," such as BLOWFISH. In PHP, this can be done using the crypt() function.

function myhash($password, $unique_salt) {

	// the salt for blowfish should be 22 characters long

	return crypt($password, '$2a$10$'.$unique_salt);

}

The second parameter to the crypt() function contains some values separated by the dollar sign ($).

The first value is '$2a', which indicates that we will be using the BLOWFISH algorithm.

The second value, '$10' in this case, is the "cost parameter". This is the base-2 logarithm of how many iterations it will run (10 => 2^10 = 1024 iterations.) This number can range between 04 and 31.

Let's run an example:

function myhash($password, $unique_salt) {
	return crypt($password, '$2a$10$'.$unique_salt);

}
function unique_salt() {
	return substr(sha1(mt_rand()),0,22);
}

$password = "verysecret";

echo myhash($password, unique_salt());
// result: $2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC

The resulting hash contains the algorithm ($2a), the cost parameter ($10), and the 22 character salt that was used. The rest of it is the calculated hash. Let's run a test:

// assume this was pulled from the database
$hash = '$2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC';

// assume this is the password the user entered to log back in
$password = "verysecret";

if (check_password($hash, $password)) {
	echo "Access Granted!";
} else {
	echo "Access Denied!";
}

function check_password($hash, $password) {

	// first 29 characters include algorithm, cost and salt
	// let's call it $full_salt
	$full_salt = substr($hash, 0, 29);

	// run the hash function on $password
	$new_hash = crypt($password, $full_salt);

	// returns true or false
	return ($hash == $new_hash);
}

When we run this, we see "Access Granted!"


8. Putting it Together

With all of the above in mind, let's write a utility class based on what we learned so far:

class PassHash {

	// blowfish
	private static $algo = '$2a';

	// cost parameter
	private static $cost = '$10';

	// mainly for internal use
	public static function unique_salt() {
		return substr(sha1(mt_rand()),0,22);
	}

	// this will be used to generate a hash
	public static function hash($password) {

		return crypt($password,
					self::$algo .
					self::$cost .
					'$' . self::unique_salt());

	}

	// this will be used to compare a password against a hash
	public static function check_password($hash, $password) {

		$full_salt = substr($hash, 0, 29);

		$new_hash = crypt($password, $full_salt);

		return ($hash == $new_hash);

	}

}

Here is the usage during user registration:

// include the class
require ("PassHash.php");

// read all form input from $_POST
// ...

// do your regular form validation stuff
// ...

// hash the password
$pass_hash = PassHash::hash($_POST['password']);

// store all user info in the DB, excluding $_POST['password']
// store $pass_hash instead
// ...

And here is the usage during a user login process:

// include the class
require ("PassHash.php");

// read all form input from $_POST
// ...

// fetch the user record based on $_POST['username']  or similar
// ...

// check the password the user tried to login with
if (PassHash::check_password($user['pass_hash'], $_POST['password']) {
	// grant access
	// ...
} else {
	// deny access
	// ...
}

9. A Note on Blowfish Availability

The Blowfish algorithm may not be implemented in all systems, even though it is quite popular by now. You may check your system with this code:

if (CRYPT_BLOWFISH == 1) {
	echo "Yes";
} else {
	echo "No";
}

However, as of PHP 5.3, you do not need to worry; PHP ships with this implementation built in.


Conclusion

This method of hashing passwords should be solid enough for most web applications. That said, don't forget: you can also require that your members use stronger passwords, by enforcing minimum lengths, mixed characters, digits & special characters.

A question to you, reader: how do you hash your passwords? Can you recommend any improvements over this implementation?

Add Comment

Discussion 115 Comments

Comment Page 1 of 21 2
  1. piyanistill says:

    ilginç bir yazı olmuş hiç bişi anlamadım ama

  2. Shane says:

    Excellent article! Your thoroughness is impressive and very helpful.

  3. Jayce says:

    I think you have alot more to worry about if someone can steal your database or your servers.

    • Jonathon says:

      True, but you do have one less thing to worry about…and not having to worry about all of your users passwords being easily accessible could help save you some public humiliation.

  4. Fabian says:

    Excellent article!

    Well written and it is really great how you give examples how each protection mechanism can be broken.

    Best Wishes,

    Fabian (LionsAd)

  5. Marco says:

    Very nice summary for developers starting out in web application security.

    One final note I would add is optional login throttling. A naive approach would be to just lockout for some number of minutes after X unsuccessful attempts, but I prefer just slapping a reCaptcha on the login form after those number of attempts instead.

  6. We’re using a sha512 encryption with a double 32bits salt.

    Double means we salt and encrypt our password twice, 1 static salt defined in our sourcecode and 1 dynamic salt code stored in a separated database table.

    Like you said in your tutorial it’s wise to use the slowest encryption method. SHA512 and Whirpool seems to be the slowest modern cryptographic so try to use these.

    (Use the HASH function http://nl2.php.net/manual/en/function.hash.php)

    But in the end I’ve to say that you can’t be too hysterical about storing passwords. When you really have a high-risk application with top secret stuff, you should use alternatives way to grant access to your users, like external devices.

    I also think there’s a responsibility for the end-users. I don’t like to ask my users to use at least 8 chars, it’s really their own decession. I recommend using passwords managers (Like 1password, LastPass) to generate unique passwords for every single service you use. in this case you can generate a 24 char password without remembering them.

  7. Very interesting article. Maybe I will start using the technique. I don’t have any idea for improvement, but I suggest that you use character that not available on keyboard as password, such as ¶ or ф and store it using Keepass Password Safe to manage the password :)

    • Ash Menon says:

      Permana, I think that’s a brilliant idea to use non-keyboard characters. Definitely something I’d look into using later on.

      For me, what I do is to use various attributes of the original unhashed password as additional security. Example, what is the first letter, and cycle through the letters like this:

      A = 1, B = 2, and so on until E= 5, then F = 1 again

      Then take that value as N and find the (N)th character in the string and do it again, etc etc. That way it multiplies the possible password combinations by billions and makes it a lot harder to crack.

    • I really like this idea, might have to stick that into future projects.

      :D

  8. Dustin Blake says:

    Great post. Just to add, in PHP versions 5.1.2 and up you can optionally use the hash() function to hash data via a variety of different algorithms including the ones mentioned, use the hash_algo() function to retrieve a list of supported algorithms.

  9. Great tutorial! I hope we can see more security related tutorials in the future.

  10. Very concise article! You do a great job of explaining what a hash is, what a salt is, and how to implement them. Makes everything very clear.

    One thing worth exploring: Which methods are used by which open source CMS projects, and how effective are they?

  11. Brad says:

    I’m using $password = hash(‘sha512′, $password); Im not sure at which point this became available but I do know its PHP 5 +. Make sure you have room in the database structure, its long. I am not salting at this point because I have to store it but am certainly keeping that option open

    I have never used the crypt functions but am glad to see how they would be used.

    Excellent tut as usual Burak.

    • syaz says:

      That kind of hashing is as weak as you can get. It doesn’t matter if your output hash is 1 thousand letters long, if the input is only “mypassword”. An attacker just need to try common password and get by. If you’ve learned anything from this article at all, you don’t want to “keep the option open”. You *need* to do something about it.

      • Brad says:

        Its my understanding that Sha512 hasn’t been broken by itself. Its considered strong. I only use passwords that use letters, symbols and numbers such as 2{87tU5@48-f7t6w@P. That’s pretty strong.

      • syaz says:

        Again, you are missing the point. I am not arguing the strength of SHAXXX. I’m pointing out the fact that you are hashing only the password, which what this very article tell you not to. What password you use has nothing to do with what your users use. They may use “pass1234″ and you can bet it’s among the first in rainbow tables.

        With rainbow tables an attacker couldn’t care less how long your output hash is, if the input is easy. You don’t need to “break” SHA512 to use rainbow tables!

  12. Bddidy says:

    Very Handy.

    Was wondering when this sort of encryption tut was going to pop up.

  13. jason says:

    Is there any advantage to sha1(sha1(sha1($password. $salt))). Basically having multiple sha1?

    • syaz says:

      Yes, multiple hash iteration is a common way to slow down dictionary/brute force attack AFAIK. But I think you are being over paranoid since you are using salt already… hashing with password and salt should be enough.

      Though I’ve read a few times experts suggesting 1000 rounds minimum depending on the hash (I forgot if that apply to SHA1 or what).

    • Jason says:

      Double, triple hashing is worse security than a regular hash. What you’re actually doing is taking some input $passwd, converting it to a string of exactly 32 characters containing only the characters [0-9][A-F], and then hashing that. You have just greatly increased the odds of a hash collision (ie. the odds that I can guess a phrase that will hash to the same value as your password).

      • jason says:

        @jason,
        That makes sense. Thanks.

      • Chris says:

        Correct me if I’m wrong but I don’t think that is correct. The only way that would be less secure is if you know the original hashing scheme.

        If I have a hash value, and find that “1234″ hashes to that particular value, it is not of any use if the login system is using multiple hashes. Because that login system will take that first hash then hash it again, resulting in a completely different value being checked, thus proving that “1234″ really wasn’t the actual password to begin with.

      • jason says:

        @chris,
        Good point. I really don’t know the answer, that is why I asked the question. I think that if you only had 32 characters that were letters and numbers then there could be some “collision”. Remember, based on the tutorial above, two values can be different but compute to the same hash. Even though your “1234″ example may have a different hash as it goes through the login script, another value could, thus the collision.

        What I don’t understand is why 32 characters only when using sha1. I know that sha1 is limited to that, but It seems like if there where more characters, like 100-500, and not limit it to just letters and numbers but also mix in symbols, then the security would be much better. I am not an expert, but that just makes sense to me.

      • syaz says:

        Jason, that doesn’t make sense. Any hash has fixed set of characters and length. What you are saying is any and all hash is not secure because they can be collided. While it’s true in theory, it’s not feasible in practice.

        The shorter the hash bits, the easier to collide.

        Please prove that multiple rounds of hashing reduces the security, as I really cannot see how.

      • syaz says:

        @jason The reason it’s represented by hex is probably just for presentation purpose. Similar how you can present 0xFF in binary / octal / decimal. I don’t see a reason why you can’t use any representation that you like, *as long as the underlying bits are the same*. The lower the base is, the longer your hash will be. However this is just an illusion, because the underlying bits are still 160 bits, so it will take the same time to break it no matter how you represent your hash.

        If you want real longer hash, that’s the reason SHA-256/512 and friends exist.

      • Azirius says:

        I think if you hash a hash you then make it weaker ie:

        This is because of the aforementioned reason of a hash being made up of hexadecimal characters.

        However, my understanding is that if you were to hash a string, then add a random salt to it and hash that would be more secure than just hashing once with a salt because you’re not just hashing a hexadecimal string.

        I don’t pretend to be an expert, so, don’t quote me on this but I think that’s how hash iteration works somewhat. Anybody have any tips on that?

  14. Dennis says:

    Thank you Burak for this interesting article !

  15. Daniel says:

    This is a very interesting article with very valuable information. I am not sure if this is an improvement but the way I am doing it, after generating unique salt for every password, I am not using concatenation, but mixing the character from the salt with the ones from the password using an algorithm. For example it could be taking the first character from the salt and then the last character from the password then the second character from the salt and the second last character from the password and so one.

    Does this extra mixing of characters help ?

    • Tom says:

      It doesn’t matter if you can append the salt, prepend the salt, mix every other letter as you do. The point of a unique salt is that it does not allow an attacker to use a rainbow table and get a lot of your passwords. Since the salt is unique to each user, the attacker would have to re-create the rainbow table for every user.

  16. It’s a shame BCrypt isn’t mentioned as it’s unaffected by most of these problems due to the work factor introduced. Also, hashing a hash N times isn’t going to slow things down at all. Sure, it may be 1-2 ms slower but that’s different than “it’s slow now”. Take a look at the following benchmark: https://gist.github.com/781310

    As you can see generating 500 SHA512 hashes only takes 0.002176 seconds, which is 2.7 miliseconds. That’s not slow at all, in fact that’s pretty bloody fast. In the end all I have to say is “use bcrypt” and I highly recommend reading this article: http://codahale.com/how-to-safely-store-a-password/

  17. Helder says:

    It´s a good article but we i advise all to see http://www.openwall.com/phpass/, that´s the system wordpress uses and its 100% secure.

  18. Max says:

    It’s been a while since your last post! Glad that you’re writing again!

  19. Jason Gerfen says:

    Great article. People need to know these methods and why they are implemented.

  20. Kevin Roberts says:

    In the first listing for point 7, line 3 seems to be redundant ($salt = “f#@V)Hu^%Hgfds”;). Is there some point to it that I have missed?

    Excellent article.

  21. netblonde says:

    Perhaps Gawker should give this a read! ;)
    thanks burak!

  22. cscsaba says:

    Great and easy to understand article, thanks.

  23. There is a strong weakness that needs to be addressed no matter what your password hashing techniques. Imagine if an attacker found an 0day exploit and was able to gain access to your server/dbase… the attacker wouldn’t even bother trying to break passwords, they instead place a logging function before your hashing function capturing the password as plain text!

    The only way to slow them down in this case, giving you enough time to respond (patching your holes) is to have the plain text passwords sent from the html form be encrypted already. In javascript you could for example do some light encryption before the password is even sent to the server. Changing this light algorithm day to day would make things most difficult on any attack that may have overlooked this presecuring mechanism. Also you should be monitoring changes to your sites files by checking hashes/date modified of files to make sure important files aren’t being tampered with and injected with keylogging scripts.

    What is most damaging to a user is when their only password which they use for everything is leaked and now have shared thier banking/social password with the world. Your site should be completely blind to what a user inputs and not be possible to retrieve data from password hashes, just so your not liable for any damages done when you lose thier data.

  24. Evan says:

    I always like a little salt with my hash. Excellent article, I wasn’t aware of the sha1 function so thanks for this.

  25. Ha, if only this article was here two days ago when I spent about 3 hours reading up on hashing and encryption.

    Thanks as always for another brilliant article.

  26. Skye says:

    Great post. I’ve been reading a lot about this lately and this is a great explanation of the basics.

  27. fael says:

    very, very good article. thanks!

  28. Darren says:

    When dealing with hashing passwords, I don’t see how hash collision is an issue at all. If two hashes produce the same output, so what? Surely it’s only an issue with encryption?

  29. Stanman says:

    Hi,

    I rarely bother to comment articles but I have to say this was an excellent overview of the problem of hacking passwords, with the added bonus of a script to help overcome some of the issues discussed, can’t ask for more than that :)

    It’s important to know how security works and while I may never need to implement such strong options I can only hope that my bank and other financial institutions continue to provide the strongest protection possible.

  30. Ryan says:

    This is a great article, your did wonderful job at breaking down and explaining a difficult subject. Thanks!

  31. Ben says:

    Perfect – this a great article. Thanks a ton, make more like it!

  32. Im using sha1(md5($password . $salt));. Any thoughts?

  33. Vijay Joshi says:

    Excellent article. And thanks for providing so much detailed explanation.

  34. BunjiGum says:

    Thanks for writing a great article! Cheers!^^

  35. Great article as always Burak. I’m forever thinking of ways to encrypt information when dealing with user data and it’s nice to see how other people go about it.

  36. Kevin says:

    Some important point made in this article.

    I have one issue in mind though. If someone steals the database then they have access to all the user data in that database regardless of figuring out their password via rainbow tables. Also, if they can steal the database, then they can steal the source code that shows how the hash was calculated.

    I believe your only as strong as your weakest link and in this case its people’s choice of passwords, so enforcing stronger passwords has more weight that hash/salt methods.

    • Dustin says:

      “if they can steal the database, then they can steal the source code that shows how the hash was calculated.”

      Thats not ‘always’ true. SQL Injection can dump tables but it isn’t going to give the attacker the source code of the site.

      And if they have access to the source code and the database then why on earth would they need the passwords for other members on the particular website. Even with knowing how the hash is calculated it will still take a time-consuming effort to run the hashes against rainbow tables with the salt applied and that still won’t guarantee success all the time.

    • Burak says:
      Author

      The way the hash was calculated is actually in the hash itself (the salt, the algorithm, the cost factor). The attacker doesn’t even need your source code to see how you calculate the hashes.

      That is all irrelevant. When you have a good hashing method, it is equally hard to break it, even if the attacker knows your hashing method.

  37. Andrew says:

    Nice read.

    Im currently using this piece $user-&ltpassword = hash_hmac(‘sha1′, $password, $pass_salt);

  38. Nikush says:

    Awesome article dude!

  39. andy says:

    I think using a slower hash is overkill unless your the government or a bank. I think that only under perfectly ideal conditions can a highly trafficked server do 1 billion hashes a second for a single process. In reality running a hash 1,000 times will show visible lag time on page load.

    • Burak says:
      Author

      Many people use the same password everywhere. So it doesn’t matter where it is stolen from. It should still have a strong hash.

      Slow hashing will only slow down the login process by maybe about 0.2 seconds at most. Only happens once per visit. None of the other page loads are affected.

  40. Excelent article Burak.
    Very well written and illustrated.

    Thank you!

  41. Z A K says:

    Great article! A much pleasant read with a topic that could have gone way over the head, yet you keep it on the ground and explained it very well.

    Thanks!

  42. John says:

    I wouldn’t suggest using blowfish or any other encryption mechanism to store passwords. If they have the database, they probably can get your source and key, and then they can decrypt anything they want. For that matter all the user data is in the database anyway.

    Also hashing your hash does increase collision possibilities, in the end more passwords will be able to create your final result if you hash a hash. At least that is how it has been explained to me. I am not smart enough to create these algorithms.

  43. John S says:

    While this is a useful server-side scheme and is well-explained, the other major hurdle has to do with exposing the password on the network in the first place.

    Those with higher-value websites (or high degrees of rational paranoia) should probably solve this wire problem with a TLS (SSL for example). However this is overkill for many of the medium value websites that are often in demand.

    I was faced with this challege myself awhile ago, and decided to user forms based security and the SHA1 algorithm. Only requirement is that the browser is running Javascript so the form can be encrypted properly. Then the encrypted username and password are retrieved from the database, and compared with the hashed credential sent back from the browser. If they match the user is authenticated. As importnat though is assuring the passwords never appear on the wire in the clear. While my forms based approach solves this at authentication time, there is the real problem of password changes. I have noticed that otherwise well-engineered authentication algorithms sometimes use clear text passwords for password change purposes. This seems unwise. I have implemented a scheme which sends the difference between two hashed username / password hashes across the wire instead. Without the original hashed username and password the delta value is useless. And it is very easy to reconstruct the new hashed credential on the server side to store it in the security database.

  44. Dieter says:

    I don’t really get the idea of using salt or any technique to influence the hash being stored. Since all user (read: hacker input) goes through the same funnel any input is treated the same.

    So:

    User types: strongpassword => System generates a “salted” hash result = x

    Hacker types: collidingpassword => System generates a “salted” hash result = x

    Anyone?

  45. Dieter says:

    Added to my previous question. In theory collision is always possible, but in real depending on machinepower.

    Would it help to look at the byte code, make some sort of math formula from the ones and zeros and add that to the check. In other words not only check the hashed string but also the outcome of a math based bytecode calculation to prevent collision?

  46. Nicki says:

    This is great Tutorials

  47. Great article on Hashing :) I’ve never really implemented making hashes longer, so now I know that it’s good practice to iterate your hashes.

    Thanks!

Comment Page 1 of 21 2

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.