3

My database stores unique salts for every user.

I'm creating a login script in php for an application where each user has it's own unique salt and here's how I plan to implement the login.

  1. User enters details and sends them
  2. Username is sent and script check if it exists
  3. If it does then returns the salt for that user otherwise general error is returned

I need the script to return the salt for that user because otherwise how would my app verify that the submitted password is correct when it cannot hash the password without the salt and send it back?

Now here's what I'm unsure about. Does it matter whether the salt is encrypted or not because a hacker could just see what it is and see the password hash and maybe could do something with it. Should I encrypt the salt before I send it?

Maybe I'm not understanding/overlooking something in the replies below.

Advice needed please.

Nubcake
  • 397
  • 2
  • 7
  • 18
  • Using salts + random key will make it harder for a hacker to crack the encryption, as they will have to sit down their manually and figure out the salt for the user, then figure out the key; and then finally start to decrypt it – Daryl Gill Apr 13 '13 at 23:00
  • Or you can implement PHPASS http://www.openwall.com/phpass/ and do it in the right way! – Twisted1919 Apr 13 '13 at 23:02
  • @DarylGill That's not really what I'm asking , I'm saying should I encrypt the salt ? Or is that what you are saying to encrypt it ? :S – Nubcake Apr 13 '13 at 23:02
  • Why are you transmitting the salt? – JRL Apr 13 '13 at 23:02
  • The idea of salt is that it makes it hard for a hacker to use rainbow tables - precomputed hashes of commonly used passwords. Since the hash uses the salt and the password, there is no lookup table big enough to precompute everything. – Floris Apr 13 '13 at 23:03
  • no. you can't encrypt the salt, because you need the salt to check for passwords. e.g. if you've stored `hash(password + salt)` in your db, then when a user logs in you, need to check `stored hash == hash(entered password + salt)`, otherwise it'd be impossible to ever match the login – Marc B Apr 13 '13 at 23:03
  • I would recommend using the solution from [crackstation.net](http://crackstation.net/hashing-security.htm#phpsourcecode). – Mason240 Apr 13 '13 at 23:03
  • Each user has it's own unique salt so I need to get it so the app can hash it. – Nubcake Apr 13 '13 at 23:03
  • @MarcB So the script should send the salt plainly to the app ? – Nubcake Apr 13 '13 at 23:05
  • 1
    Nubcake, I'm asking you *why* you are trying to transmit the salt over some kind of unsecured communication. The authentication should always happen where the salt is stored. – JRL Apr 13 '13 at 23:05
  • I'm sure I mentioned in my OP Basically each user in the db has their own unique salt right? How am I supposed to verify if their password is correct if I cannot hash it without getting the salt first from the db? – Nubcake Apr 13 '13 at 23:06
  • `select id, user from users where stored_hash=md5(concat(user_salt, $password)) and username=$username`. you can refer/use other fields in a given record in a select statement. – Marc B Apr 13 '13 at 23:08
  • The actual authentication should happen as close to the database as possible. Don't send the hash + salt to the client and then let it hash their password and compare. That's terrible. Send their password to your server and hash + compare it there. – JRL Apr 13 '13 at 23:09
  • @JRL Sorry if I'm not understanding this but I get that the authentication should happen on the server side but you're telling me I should send the password first -> Not hashed but encrypted because I cannot hash it without the salt that I don't have yet? – Nubcake Apr 13 '13 at 23:12
  • @Nubcake Typically if you want to protect information in transit (like a password) over HTTP, you use SSL. What you're talking about doing will only really be effective against Man-in-the-middle attacks, and then only mildly. You don't want to expose the inside of your DB like that. – JRL Apr 13 '13 at 23:15
  • @JRL I'm not sure you understand my problem ; When the user submits their details , the username is sent to verify if it exists. Ok now , the password is the problem because I cannot send it plain text or encrypted but it needs to be hashed with it's unique salt that is stored in the db. It's stored in the db so i need to retrieve it so I can hash the password with it and send it for verification. Do you get that? – Nubcake Apr 13 '13 at 23:18
  • @MarcB You do know that I'm trying to receive the salt first right? – Nubcake Apr 13 '13 at 23:26
  • When a user logs in, you want to send both the username and the password to your server. From there, you `select` the username and the salt from your DB, and within the same script, you do your hashing for the password, and then do another `select` where `uname=user` and `pass=hashedPass`. If you get a result, you return `true` or something similar to your app saying that the log-in was successful. You don't need to be sending it back and forth to the app itself. – Jon Apr 13 '13 at 23:31
  • @Jon I am doing what you are saying i.e getting the username and salt but what do you mean by 'hashing for the password' I don't have it on the server side yet. – Nubcake Apr 13 '13 at 23:34
  • @Nubcake There is no point of sending the salt to the app to do the hashing, then you would get the hashed password to do a straight check with the DB - meaning that if anyone get's a hold of the DB, they can get authenticated because all they'll need is the hash to log in anyways. You want the password sent with the username for the log-in and return to the app a true/false type of thing for whether or not the user was authenticated. – Jon Apr 13 '13 at 23:37
  • @Jon Following your logic , how would I go about sending data (specifically the password) to the server on a standard connection? – Nubcake Apr 13 '13 at 23:40
  • @Nubcake you can opt to do a public-key encryption scheme, public key is in your app, private key to decrypt is on your server. Though, even with a standard connection you are only susceptible to a man-in-the-middle attack which is less common than unauthorized authentication which you leave yourself open to by only verifying based on what is in the DB to begin with. If security is paramount in your application, then you need to get SSL going on your server - but you want the hashing of the password with salt to be done server-side. If you don't want a plain text password sent [MORE] – Jon Apr 13 '13 at 23:46
  • to your server, you can do a basic hash before sending it to the server and do the actual hash+pass that you get from the app server side. But again, you don't want your app doing the legwork of creating the entire authentication scheme, you want that done on the server. – Jon Apr 13 '13 at 23:47
  • @Jon Security is not that paramount in my app so I don't want to use SSL but I just want to be aware , are you saying that private/public key encryption is used in situations like this ? I.e for someone like me who stores password salts on the db and needs to verify authentication but cannot send a hash because they don't have the salt yet so they use that. Is it more secure that what I'm doing ? – Nubcake Apr 13 '13 at 23:50
  • @Nubcake it is more secure in that for a man-in-the-middle attack needs one more step (getting the private key to decrypt the info sent), but most would send it in plain-text and do the authentication/hashing on the server as man-in-the-middle attacks aren't that common, and require timing in order to capture when the password is being sent. To compare - think of a web page that doesn't have SSL but you still log in to it with a username/pass. It would be the same principle for the app, as the pass is still sent in plain-text. – Jon Apr 13 '13 at 23:54

1 Answers1

1

It doesn't matter if your salts are hashed or left as plain strings - the important point is that salting a password prevents the direct use of dictionary/rainbow table attacks to brute-force crack passwords. An added advantage is that each user has a different hashed password as a result.

Salts are randomly generated string that are created server-side and don't involve any kind of transmission to or from the browser.

On your server:

  // Password from form
  $pw = $_GET['password'];

  // Generate salt using unique values
  $salt = (rand(8).$registration_date.$username);

  // Password to be hashed
  $pwthb = ($pw.$salt);

If a hacker gains access to your databases, then your game is over in the majority of cases as you need to store the initial random salt to hash it for comparison.

A simple example:

  1. User enters initial password in browser upon registration
  2. On your server, password is combined with a unique salt, hashed and stored as password in DB
  3. Salt is stored in DB

Note: hashing can be done using PHP or using MySQL/DB functions

When the user returns:

  1. User enters password in browser
  2. Grab salt from DB and combine with the password entered
  3. Hash password+salt and compare with stored/hashed password
  4. If they match: authenticate

In terms of further reading, It's probably worth looking over the following:

Community
  • 1
  • 1
nickhar
  • 19,981
  • 12
  • 60
  • 73
  • Just a point of note, it isn't 'encrypted', rather it is 'hashed'. Encryption means that it can be decrypted, whereas hashes are 'one-way' and can't be broken back down to the original parts. A small but significant difference when dealing with user passwords. ^^ – Jon Apr 14 '13 at 00:02
  • 2
    Another small point, if you hash it correctly, the game is not up if access to the DB is gained (use `bcrypt` or stretch the hash significantly so the computational time is at least 1-2 seconds for the creation of the hash stored). The longer it takes to produce the hashed password going in to the DB the longer it will take to try and brute force the actual password from it even if the salt is known. – Jon Apr 14 '13 at 00:04
  • @jon Point noted, just trying to keep it simple. – nickhar Apr 14 '13 at 00:06