Jump to content

How to Safely Store Passwords


doubledee

Recommended Posts

What do I need to do to *safely* capture and store User Passwords in a Registration Form?

 

There was a thread that I started a few months ago where someone had given a really good response talking about "Salt" and so on, but for the life of me I cannot find that info.

 

Nonetheless, I need some help getting my head back into this topic!

 

My Registration Form is complete, and the last thing I need to do is make sure Users enter a "Strong Password" and then I need to store that somewhere, somehow, in the most *secure* manner possible...

 

Thanks,

 

 

Debbie

 

Link to comment
Share on other sites

  • Replies 54
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

A Salt is a small string containing random characters that are not known by the user. But you can use both md5() and salting to safely secure your users passwords. 

 

Example:

<?php 
$pass = mysql_real_escape_string($_POST['password']);
$salt = 'b7lLkm755246zZlaBkl44zc2';
$password = md5($salt . $pass);

$sql = mysql_query("INSERT INTO table (password) VALUES ('$password')";
?>

 

 

What the code above does is it first escapes special characters in the string/user's password. Then it md5's the Salt you created along with the user's password, hence it makes the password virtually impossible to crack. 

 

 

 

 

 

 

 

 

Link to comment
Share on other sites

I don't understand the reasoning behind salt.  To keep it simple, let's say the password is "Jim" and salt is "1234".  These are combined to "1234Jim" (putting salt in front), then encoded.  When a person logs in they add password "Jim" it's added to the salt, encoded and passed for query.  My point is, all they're doing is entering "Jim" and so how is salt helping to secure things?

Link to comment
Share on other sites

I don't understand the reasoning behind salt.  To keep it simple, let's say the password is "Jim" and salt is "1234".  These are combined to "1234Jim" (putting salt in front), then encoded.  When a person logs in they add password "Jim" it's added to the salt, encoded and passed for query.  My point is, all they're doing is entering "Jim" and so how is salt helping to secure things?

 

I believe there is a concept of "Rainbow Tables" where hackers store common passwords and use "Dictionary Attacks".

 

So, "password" might be in the "Rainbow Table" and thus an easy choice, but "623901password" would NOT be in the "Rainbow Table" and thus slightly more secure.

 

 

Debbie

 

Link to comment
Share on other sites

mysql_real_escape_string($_POST['password']);

 

What is the benefit of using mysql_real_escape_string()??

 

Is it really necessary??

 

 

Debbie

 

From W3schools:

 

The mysql_real_escape_string() function escapes special characters in a string for use in an SQL statement

 

The following characters are affected:

 

\x00

\n

\r

\

'

"

\x1a

This function returns the escaped string on success, or FALSE on failure.

 

It basically 'escapes' characters from being inserted to your queries and preventing somewhat sql injection. 

 

Link to comment
Share on other sites

What you should do

 

    Use a cryptographically strong hashing function like SHA-1 or even SHA-256 (see PHP’s hashfunction).

    Use a long and random salt for each password.

    Use a slow hashing algorithm to make brute force attacks near impossible.

    Regenerate the hash every time a users logs in.

Example:

<?php
$username = 'Admin';
$password = 'gf45_gdf#4hg';

// Create a 256 bit (64 characters) long random salt
// Let's add 'something random' and the username
// to the salt as well for added security
$salt = hash('sha256', uniqid(mt_rand(), true) . 'something random' . strtolower($username));

// Prefix the password with the salt
$hash = $salt . $password;

// Hash the salted password a bunch of times
for ( $i = 0; $i < 100000; $i ++ )
{
    $hash = hash('sha256', $hash);
}

// Prefix the hash with the salt so we can find it back later
$hash = $salt . $hash;

/* Value:
* e31f453ab964ec17e1e68faacbb64f05bccceb179858b4c482c1b182ff1e440e
* f1e10feb5b86c6d367e4eb8f90f2cde5648a7db3df8526878f20a77eed00c703
*/

?>

Link to comment
Share on other sites

From W3schools:

 

The mysql_real_escape_string() function escapes special characters in a string for use in an SQL statement

 

The following characters are affected:

 

\x00

\n

\r

\

'

"

\x1a

This function returns the escaped string on success, or FALSE on failure.

 

It basically 'escapes' characters from being inserted to your queries and preventing somewhat sql injection.

 

I use Prepared Statements, so I don't believe that I need to worry about that.

 

 

Debbie

 

 

Link to comment
Share on other sites

I don't understand the reasoning behind salt.  To keep it simple, let's say the password is "Jim" and salt is "1234".  These are combined to "1234Jim" (putting salt in front), then encoded.  When a person logs in they add password "Jim" it's added to the salt, encoded and passed for query.  My point is, all they're doing is entering "Jim" and so how is salt helping to secure things?

 

Salts mean that multiple users with the same password will have different hashes, therefore making rainbow tables useless (you would have to create a rainbow table for each user).

 

md5() and sha1() are garbage for storing passwords.

 

And so you recommend WHAT instead??

 

 

Debbie

 

 

A longer, slower hashing algorithm. Like SHA512 or bcrypt.

 

From W3schools:

 

The mysql_real_escape_string() function escapes special characters in a string for use in an SQL statement

 

The following characters are affected:

 

\x00

\n

\r

\

'

"

\x1a

This function returns the escaped string on success, or FALSE on failure.

 

It basically 'escapes' characters from being inserted to your queries and preventing somewhat sql injection.

 

I use Prepared Statements, so I don't believe that I need to worry about that.

 

 

Debbie

 

You don't.

Link to comment
Share on other sites

What you should do

 

    Use a cryptographically strong hashing function like SHA-1 or even SHA-256 (see PHP’s hashfunction).

 

Is SHA-1 good enough?

 

Some people say it can be hacked.

 

 

    Use a slow hashing algorithm to make brute force attacks near impossible.

 

What do you mean?

 

    Regenerate the hash every time a users logs in.

 

You mean generate a new Hashed Password every time they log in??? 

 

Example:

<?php

$username = 'Admin';

$password = 'gf45_gdf#4hg';

 

// Create a 256 bit (64 characters) long random salt

 

I thought there were 8-bits in a byte and that a character was a byte?

 

 

// Let's add 'something random' and the username

// to the salt as well for added security

$salt = hash('sha256', uniqid(mt_rand(), true) . 'something random' . strtolower($username));

 

Why all the craziness?!

 

Also, is this a concern...

http://dev.mybboard.net/issues/843

 

 

// Prefix the password with the salt

$hash = $salt . $password;

 

// Hash the salted password a bunch of times

for ( $i = 0; $i < 100000; $i ++ )

{

    $hash = hash('sha256', $hash);

}

 

Why even more craziness??? 

 

One thousand times?! :o

 

 

// Prefix the hash with the salt so we can find it back later

$hash = $salt . $hash;

 

What do you mean?

 

 

 

Debbie

 

Link to comment
Share on other sites

I don't understand the reasoning behind salt.  To keep it simple, let's say the password is "Jim" and salt is "1234".  These are combined to "1234Jim" (putting salt in front), then encoded.  When a person logs in they add password "Jim" it's added to the salt, encoded and passed for query.  My point is, all they're doing is entering "Jim" and so how is salt helping to secure things?

 

Salts mean that multiple users with the same password will have different hashes, therefore making rainbow tables useless (you would have to create a rainbow table for each user).

 

I don't think that is correct.

 

If you and I both had "santa_claus" for our passwords, wouldn't the same Hash generate DIFFERENT hashed values 99.999% of the time regardless of whether a Salt was used?

 

I think the Salt prevents Rainbow Tables and Brute FOrece Attacks, but has nothing to do with people having the same passwords...

 

 

md5() and sha1() are garbage for storing passwords.

 

And so you recommend WHAT instead??

 

 

Debbie

 

 

A longer, slower hashing algorithm. Like SHA512 or bcrypt.

 

What do you mean by "slower hashing algorithm"??

 

 

Debbie

 

Link to comment
Share on other sites

bcrypt uses the Eksblowfish algorithm to hash passwords. While the encryption phase of Eksblowfish and Blowfish are exactly the same, the key schedule phase of Eksblowfish ensures that any subsequent state depends on both salt and key (user password), and no state can be precomputed without the knowledge of both. Because of this key difference, bcrypt is a one-way hashing algorithm. You cannot retrieve the plain text password without already knowing the salt, rounds and key (password).

Link to comment
Share on other sites

I don't understand the reasoning behind salt.  To keep it simple, let's say the password is "Jim" and salt is "1234".  These are combined to "1234Jim" (putting salt in front), then encoded.  When a person logs in they add password "Jim" it's added to the salt, encoded and passed for query.  My point is, all they're doing is entering "Jim" and so how is salt helping to secure things?

 

Salts mean that multiple users with the same password will have different hashes, therefore making rainbow tables useless (you would have to create a rainbow table for each user).

 

I don't think that is correct.

 

If you and I both had "santa_claus" for our passwords, wouldn't the same Hash generate DIFFERENT hashed values 99.999% of the time regardless of whether a Salt was used?

 

No. If you MD5 "santa_claus" it's always going to be the same hash, unless a salt is used.

 

I think the Salt prevents Rainbow Tables and Brute FOrece Attacks, but has nothing to do with people having the same passwords...

 

Without using a salt all you need is a rainbow table and you can easily reveal passwords based on their hash. If multiple people have the password "santa_claus", then multiple people will have identical hashes. This cuts down on the amount of work required to uncover passwords, because they can reveal multiple passwords with a single hash.

 

Using salts means that rainbow tables are only effective if you create one for each individual user with their unique salts. Obviously, this would require considerable time and resources... rainbow tables are quite large.

 

 

md5() and sha1() are garbage for storing passwords.

 

And so you recommend WHAT instead??

 

 

Debbie

 

 

A longer, slower hashing algorithm. Like SHA512 or bcrypt.

 

What do you mean by "slower hashing algorithm"??

 

 

Debbie

 

 

MD5 and SHA1 are not secure password storing hashes because they are fast. A modern computer can generate MD5 or SHA1 hashes very, very fast. Which means that finding collisions takes hours and not years.

 

A slower algorithm (like sha512 or bcrypt) takes considerably more time to compute and is therefore more secure. Creating rainbow tables or finding collisions would take a very long time compared to md5 or sha1.

 

Coupling this with hash_hmac should be good enough for most applications. hash_hmac makes use of a cryptographic key when making hashes. What this means is that in order to use rainbow tables or brute force hashes the attacker would also need the cryptographic key residing in the file system. So not only does the attacker need to compromise the database, but the file system as well.

Link to comment
Share on other sites

I don't understand the reasoning behind salt.  To keep it simple, let's say the password is "Jim" and salt is "1234".  These are combined to "1234Jim" (putting salt in front), then encoded.  When a person logs in they add password "Jim" it's added to the salt, encoded and passed for query.  My point is, all they're doing is entering "Jim" and so how is salt helping to secure things?

 

Salts mean that multiple users with the same password will have different hashes, therefore making rainbow tables useless (you would have to create a rainbow table for each user).

 

I don't think that is correct.

 

That actually is correct, provided a unique salt is used for each user.

 

If you and I both had "santa_claus" for our passwords, wouldn't the same Hash generate DIFFERENT hashed values 99.999% of the time regardless of whether a Salt was used?

 

No, a hashing algorithm will generate the same value for the same string every time. That's why salts should be unique.

 

I think the Salt prevents Rainbow Tables and Brute FOrece Attacks, but has nothing to do with people having the same passwords...

 

Salts help prevent "reverse engineering" of the hash values in your database in the event a malicious user was to obtain the data vie a SQL injection attack, etc. Hashes cannot be "decrypted" per se, but there are rainbow tables that hold the hash values that correspond to common dictionary words, names, places, etc. Then the malicious user simply has to compare the hashes to the table to find values that match.

 

A brute force, or dictionary attack is not protected against by salting the hashes stored in the database. Since the mailcious user is simply guessing at passwords, then submitting them to your processing script, this is no different than a user entering their password in your login form; the salt is applied after that. This is where using a slower hashing algorithm comes into play. If md5() runs in 1/10000 of a second, the attacker could theoretically try 10000 passwords in a second and see if any of them work, or 36 million in an hour. If SHA512 takes 1/50 of a second to run, the attacker could only try 180,000 in an hour. Adding a sleep() delay in the login script makes it even less convenient for an attacker to try to guess passwords. Of course, you should utilize an account "lockout" feature in the event a user fails to authenticate x number of times in row, or within a certian time period.

 

md5() and sha1() are garbage for storing passwords.

 

And so you recommend WHAT instead??

 

 

Debbie

 

 

A longer, slower hashing algorithm. Like SHA512 or bcrypt.

 

What do you mean by "slower hashing algorithm"??

 

 

Debbie

 

 

Link to comment
Share on other sites

<?php
$username = 'Admin';
$password = 'gf45_gdf#4hg';

// Create a 256 bit (64 characters) long random salt
// Let's add 'something random' and the username
// to the salt as well for added security
$salt = hash('sha256', uniqid(mt_rand(), true) . 'something random' . strtolower($username));

// Prefix the password with the salt
$hash = $salt . $password;

// Hash the salted password a bunch of times
for ( $i = 0; $i < 100000; $i ++ )
{
    $hash = hash('sha256', $hash);
}

// Prefix the hash with the salt so we can find it back later
$hash = $salt . $hash; 
?>

 

How do I log back in the User?

 

I have a "create_account.php" script with your suggested code above and a "log_in.php" script.

 

As far as I can see, I need to pass the $salt to the "log_in.php" script, because if I calculate it in the 2nd script, then it will always be different due to this...

uniqid(mt_rand()

 

Also, I am not quite getting what I should be storing in my database...  :shrug:

 

Thanks,

 

 

Debbie

 

Link to comment
Share on other sites

Of course you'll need the salt, that's the whole point. You need to store the salt in the users table and retrieve it when they try to log in. There's a plethora of tutorials out there that demonstrate this. In fact I think there was a few other topics on the matter not too long ago on these forums.

 

Also, keep in mind that hashing a hash 100,000 times isn't doing any good at all except waste server resources.

Link to comment
Share on other sites

Of course you'll need the salt, that's the whole point. You need to store the salt in the users table and retrieve it when they try to log in. There's a plethora of tutorials out there that demonstrate this. In fact I think there was a few other topics on the matter not too long ago on these forums.

 

Care to share any links?

 

 

Also, keep in mind that hashing a hash 100,000 times isn't doing any good at all except waste server resources.

 

Yeah, I wonder about that...

 

 

Debbie

 

Link to comment
Share on other sites

How hard is it to figure out?  You've seen how to create a salt and salted and hashed password.  You store those in the users table along with the rest of their info upon registration.  For login (pseudocode):

 

 

if entered username exists in the db:
   retrieve salt and password for that username

   if salt + entered password == retrieved password:
      log user in
   else:
      bad password

else:
   bad username

Link to comment
Share on other sites

This should get you started...

 

users table

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) NOT NULL,
  `password` char(128) NOT NULL,
  `salt` char(10) NOT NULL,
  PRIMARY KEY (`id`)
)

 

the hashing function

function hash_password($password, $salt = null)
{
if (!is_null($salt))
	$salt = substr(sha1(uniqid(mt_rand(), true)), 0, 10);

// this should be a long, random string
// stored somewhere safe
$key = 'abcdef';

$hash = hash_hmac('sha512', $password, $key);

return array($hash, $salt);
}

 

register.php

if (!empty($_POST)) {
$username = $_POST['username'];
$password = $_POST['password'];

if (!empty($username) && !empty($password)) {
	list($hash, $salt) = hash_password($password);

	// INSERT INTO users VALUES (0, $username, $hash, $salt);
}
}

 

login.php

if (!empty($_POST)) {
$username = $_POST['username'];
$password = $_POST['password'];

if (!empty($username) && !empty($password)) {
	// SELECT username, password, salt
	// FROM users
	// WHERE username = $username
	// $row = fetch row

	list($hash) = hash_password($password, $row['salt']);

	if ($hash == $row['password']) {
		// hashes match, log in
	}
}
}

 

 

 

IIRC, hashing an already hashed value actually increases the chances of collision.  Could be wrong, but Ii think I read that somewhere.

 

Yeah, I remember reading a big article about why it was bad. But in my 47 seconds of Googleing for it, couldn't find it. Oh well.

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.