views:

835

answers:

5

How much more safer is this than just md5? I've just started look into password security. Im pretty new with php.

$salt = 'csdnfgksdgojnmfnb';

$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users 
                       WHERE username = '".mysql_real_escape_string($_POST['username'])."' 
                       AND password = '$password'");

if (mysql_num_rows($result) < 1) {
    /* Access denied */
    echo "The username or password you entered is incorrect.";

} else {
    $_SESSION['id'] = mysql_result($result, 0, 'id');
 #header("Location: ./");
 echo "Hello $_SESSION[id]!"; 
}

Some input or comments would be nice

Thank you

+9  A: 

You users will be much safer if you used parameterized queries instead of concatenating SQL statements.

And salt should be unique for each user and should be stored along with password hash.

Anton Gogolev
how do u suggest i generate these unique salts
Rebar
@Rebar - see my answer.
thephpdeveloper
There is a good article about security in PHP at Nettuts+, password salting is also mentioned. Maybe you should take a look at: http://net.tutsplus.com/tutorials/php/simple-techniques-to-lock-down-your-website/
Fábio Antunes
+1  A: 

That's fine with me. Mr Atwood wrote about the strength of MD5 against rainbow tables, and basically with a long salt like that you're sitting pretty (though some random punctuation/numbers, it could improve it).

You could also look at SHA-1, which seems to be getting more popular these days.

nickf
The note at the bottom of Mr Atwood's post (in red) links off to another post from a security practicioner that states using MD5, SHA1 and other fast hashes for storing passwords is very wrong.
sipwiz
It is only wrong in that users can brute-force it quicker. 'slow' hashes are usually made slow by introducing a wait. This is false security. Better to limit the number of times someone can attempt to login.
Matthew Scharley
@Matthew Scharley: I don't agree that the additional effort imposed by expensive password hashing algorithms is false security. It's to guard against brute-forcing of easily guessable passwords. If you're limiting login attempts, then you're protecting against the same thing (although a bit more effectively). But if an adversary has access to the DB stored hashes, he will be able to brute force such (easily guessable) passwords fairly quickly (depending on how easily guessable). The default for the SHA-256 crypt algorithm is 10000 round, so that would make it 10000 times more difficult.
Inshallah
The slow hashes are actually made by iterating a fast one a very large number of times, and shuffling the data around in between each iteration. The goal is to ensure that even if the bad guy gets a copy of your password hashes, he has to burn a considerable amount of CPU time to test his dictionary against your hashes.
caf
@caf: I believe the bcrypt algorithm makes use of the parameterizable expensiveness of the Eksblowfish key scheduling; not entirely sure how this works, but key scheduling is often a very expensive operation done during the init a cipher context object, before any encryption is done.
Inshallah
Inshallah: This is true - the bcrypt algorithm is a different design, where the underlying crypto primitive is a block cipher rather than a hash function. I was referring to schemes based on hash functions, like PHK's MD5 crypt().
caf
+6  A: 

You can use the pwd class (http://code.google.com/p/samstyle-php-framework/source/browse/trunk/class/pwd.class.php) to help you generate a 72-characters hash which includes salting.

You can verify the hashes and compare against passwords whether they are the same or not.

Understanding salting:

A salt is a random string that is generated to make each hash unique even if the password is the same.

So when you generate a hash, you do this:

<?php
// generates a 8 character hexadecimal CRC32 string
function crc($o){
  return str_pad(dechex(crc32($o)),8,0,STR_PAD_LEFT);
}

$salt = crc(mt_rand().time); // a unique fixed length salt
$hash = sha1($password . $salt).$salt; // generates a 40 character hash (32+8)

?>

You store the $hash off into the database.

When checking the user-entered password against the hash, you do this:

<?php

$hash = $TheHashFromDatabase;

$salt = substr($hash,-8);
$generated_hash = sha1($_POST['user_pwd'] . $salt).$salt;

if($generated_hash == $hash){
  // logged in - password is correct
}
?>
thephpdeveloper
The Google code pwd.class.php uses the MD5 hashing algorithm. The MD5 hashing algorithm is not to be used for security anymore. In other words: do not use the pwd class, it is NOT secure.
Jacco
@Jacco - something good and simple for the new php beginner please.
thephpdeveloper
@Jacco - btw, study the code carefully. you can't just use the rainbow tables on it.
thephpdeveloper
Good and simple for a beginner. yes, please! So please do not recommend insecure code. Recommend a proven, widely reviewed library instead.
Jacco
"the MD5 algorithm should be considered cryptographically broken and unsuitable for further use." More information: http://www.google.com/#q=MD5+broken
Jacco
Why do you CRC the salt?! Salts are better the longer they are and the more different potential characters they have. When you hash something, different strings can produce the same hash, the shorter the hash the more collisions. You should only hash once. Store the hash in a separate field in the db.
OIS
i'm generating a short salt here for example. you can choose to sha1 it
thephpdeveloper
I was wondering what was happening with `mt_rand().time`, and then, with a little experimentation, I found that you're simply generating a random number, implicitly converting it to a string, and concatenating it to 'time' (also implicitly turned into a string). Is there any reason you do this? If you're just going to be CRC32ing it to produce a fixed-length string, the time part seems unneccesary.
Xiong Chiamiov
It is to generate a random salt based on the random number generator `mt_rand()` and `time()`.
thephpdeveloper
+3  A: 

A better way would be for each user to have a unique salt.

The benefit of having a salt is that it makes it harder for an attacker to pre-generate the MD5 signature of every dictionary word. But if an attacker learns that you have a fixed salt, they could then pre-generate the MD5 signature of every dictionary word prefixed by your fixed salt.

A better way is each time a user changes their password, your system generate a random salt and store that salt along with the user record. It makes it a bit more expensive to check the password (since you need to look up the salt before you can generate the MD5 signature) but it makes it much more difficult for an attacker to pre-generate MD5's.

R Samuel Klatchko
Salts are usually stored together with the password hash (e.g. the output of the `crypt()` function). And since you have to retrieve the password hash anyway, using a user specific salt will not make the procedure any more expensive. (Or did you mean generating a new random salt is expensive? I don't really think so.) Otherwise +1.
Inshallah
For purposes of security, you may want to provide access to the table only through stored procedures and prevent the hash from ever being returned. Instead, the client passes what it thinks is the hash and gets a success or failure flag. This allows the stored proc to log the attempt, create a session, etc.
Steven Sudit
@Inshallah - if all users have the same salt, then you can reuse the dictionary attack you use on user1 against user2. But if each user has a unique salt, you will need to generate a new dictionary for each user you want to attack.
R Samuel Klatchko
@R Samuel - that's exactly why I voted your answer up, because it recommends the best-practice strategy to avoid such attacks. My comment was meant to express my perplexity about what you said regarding the additional cost of a per-user salt, which I didn't understand at all. (since "salts are usually stored together with the password hash" any additional storage and CPU requirements for a per-user salt are so microscopic, that they need not even be mentioned...)
Inshallah
@Inshallah - I was thinking about the case where you have the database checked if the hashed password is okay (then you have one db retrieval to get the salt and a second db access to check the hashed password). You are right about the case where you download the salt/hashed password in a single retrieval and then do the comparison on the client. Sorry for the confusion.
R Samuel Klatchko
+13  A: 

The easiest way to get your password storage scheme secure is by using a standard library.

Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.

The standard library:
Take a look at: Portable PHP password hashing framework: phpass and make sure you use the CRYPT_BLOWFISH algorithm if at all possible.

example of code using phpass (v0.2):

require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

PHPass has been implemented in some quite well known projects:

  • phpBB3
  • WordPress 2.5+ as well as bbPress
  • the Drupal 7 release, (module available for Drupal 5 & 6)
  • others

The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.

For more information on password storage schemes, read Jeff`s blog post: You're Probably Storing Passwords Incorrectly

Whatever you do if you go for the 'I'll do it myself, thank you' approach, do not use MD5 anymore. It is a nice hashing algorithm, but broken for security purposes.

Currently, using crypt, with CRYPT_BLOWFISH is the best practice.
CRYPT_BLOWFISH in PHP is an implementation of the Bcrypt hash. Bcrypt is based on the Blowfish block cipher, making use of it's expensive key setup to slow the algorithm down.

Jacco
Yes, yes, a thousand times yes.
caf