views:

170

answers:

5

For a login system in php would this be a suitable outline of how it would work:

users types in username and password, clicks login button.

  1. Checks if user exists in database,
  2. if it does, then retrieve the salt for that user
  3. hash the password and salt (would this be done on the client or server side? I think client side would be better, but php is server side so how would you do this?)
  4. check value against value in database,
  5. if the values match then user has typed in correct password and they are logged in.
+3  A: 

It has to be Server Side

OM The Eternity
Only if you are not using SSL. Still, if you do it client side then the client has to know about the encryption methods of your database which is not it's responsibility. Adding to that, the client might not have scripts enabled so the whole hashing wouldn't work.
dbemerlin
Mind It Clients are Non techies... mostly... They Are Just as other general users...
OM The Eternity
+6  A: 

Checks if user exists in database, if it does then retrieve the salt for that user hash the password and salt (would this be done on the client or server side? I think client side would be better, but php is server side so how would you do this?)

The important thing to remember is that you never ever trust the user which means where authentication is concerned you should do as much as possible on the server side. Give the user as little information as possible and don't trust them with anything.

In regards to your question, the obvious point is that there is far more data transfer involved if you let the user precompute the hash. Rather than the single request and response there are 3 requests and responses required. It also increases the requirements from a browser to a browser with JavaScript enabled. Depending on your audience a lot of users can have JavaScript disabled (usually via the NoScript plugin).

Regarding security, while allowing the the user to see the salt wouldn't effect the defense against rainbow tables, showing them how you combine the salt and the password does.

Brute force attempts through the web interface are not that much of an issue anyway as hopefully you would only allow 5 (or so) login attempts per username per hour. Knowing the salt and hashing algorithm doesn't help at all (It just reduces your sever load ;) ). However if they have the database and know how to combine the salt and the hash it becomes that much easier to do a brute force attack.

While security through obscurity is no real defence, it does make your system that much harder to break, so I would reccomend that you don't attempt to do hashing on the client side.

Yacoby
+5  A: 

Checks if user exists in database, if it does then retrieve the salt for that user hash the password and salt

No. This means you are hitting your database twice.

hash the password and salt (would this be done on the client or server side? I think client side would be better

No. The point of hashing the password is so that if someone compromises your database, they can't (easily) find out what they need to send to your system (or other systems) to log in as that user.

If you hash the password before sending it to the server, then the attacker can bypass the JS and send the prehashed password read from the database to your system.

  1. User submits username and password
  2. Password is hashed with the standard salt for the system
  3. SELECT some,cols FROM your_users WHERE username=? and password=?
  4. Count the number of rows returned from the database.
David Dorward
No, the salts are used to limit the capacity of an attacker to use rainbow tables against the hashed passwords. So one salt per application would be worst than one salt per user alongside the hash.Or, to be a little more thorough, one salt for the application and one salt per user. So if the attacker compromised only your database, he'll have to first get the application hash which would require a first rainbow attack (as he knows the password of his own account, he knows everything but the application salt).
Arkh
Agree with Arkh. And since the salt is unique per user, you'd have to hit the database twice; the first time to get the salt, and the second time to check if the hash(password + salt) matches what is there in the database. If you want to avoid two trips, you may write a stored procedure.
sri
@sri why not to hash in the same query, like `MD5(concat(salt,'pass'))`?
Col. Shrapnel
No need to do two roundtrips to the database. Get the hashed password and salt from the database, then test on php side.@Col. Shrapnel. Not MD5, hmac using at least sha256, or if you have access to it bcrypt as it's slow so good against bruteforce attacks : http://codahale.com/how-to-safely-store-a-password/
Arkh
@Arg - duh. You are right, of course you don't need 2 trips to the DB.
sri
@Arkh ahaha, funny article. "given the hash and the salt from your database" :))))
Col. Shrapnel
This question was about security, so, how many times we hit the database does not concern us right now, it can be tuned later. Anyway, I don't think a standard salt for the entire system is a good idea. There should be a global key for the system as well as a unique salt per user. These two components are then hashed with the password.
Kai Sellgren
Speaking of security, I would recommend neither storing a salt along with hashes based on it or sending passwords or salts in clear text to the database since that communication could be intercepted. Instead, hash in your code and only send the hashes to the database. Also, never select the hash column from your database, only check for it or send updates/inserts!
Energiequant
A: 

Why such many moves?

  1. Check if user exists in database, with given salted hashed password
  2. if it does, then retrieve the user information

that's all

If you're talking of secure password transfer from client to the server - that's another story, you can refer to the HTTP digest authorization description for the schema. In short, it's client-side password hashing using random one-time token stored on the server side. OR SSL, of course

Col. Shrapnel
+1  A: 

You are on the right track, but let me help you improve your system.

Generate a strong random key and store it in a file above your document root:

/home/username/key
/home/username/public_html/login.php

The file should contain (pseudo) random binary data with as much strength as possible. 512-bits of random data should be quite okay.

Then generate a unique salt for each user in your system. This salt does not have to be stronger than 16-bits of random binary data.

Finally, the password hashes should be something like:

hash('sha256', $password . $salt . $key);

where the hash algorithm matters a lot. Do not use MD5 or SHA-1. Use the SHA-2 family, typically SHA-256 or SHA-512. Also, Whirlpool is a good choice.

If you want to improve your system even more, you could iteratively hash again and again like:

public static function hash($algorithm, $data, $iterations = 1, $rawOutput = false)
{
    if ($iterations < 1)
        throw new Exception('There must be at least one iteration.');

    while ($iterations--)
    {
        $data = hash($algorithm, $data, true);
    }

    return ($rawOutput ? (binary) $data : bin2hex($data));
}
Kai Sellgren
thank you! I'm not sure what you mean by the last part of your answer about iteratively hashing.
Jonathan
It's about rehashing, hashing the hash again and again. This will slow down cracking as the crackers need to rehash too.
Kai Sellgren