I'm trying to correctly do a per user and site wide salt for my passwords. Here's what I've got:

require('../../salt.php'); //this is above the web root and provides $salt variable
$pw = mysql_real_escape_string($_POST['pw']);
$per_user_salt = uniqid(mt_rand());
$site_salt = $salt //from salt.php that was required on first line
$combine = $pw . $per_user_salt . $site_salt;
$pw_to_put_in_db = hash("sha512", $combine);

Is this right? Thanks

Comments

This isn't really an answer to whether you're doing it right. (1) No need to use mysql_real_escape_string. The resultant hash() would change any invalid SQL to a letter/number. (2) Ensure you're storing your $per_user_salt in a safe, secure way to retrieve it when your users are trying to login with their password.

@Charles Sprayberry, for storing - do I need to do anything different than INSERT INTO users (per_user_salt) VALUES ($per_user_salt) ?

Written by Andypandy

@Andypandy - Assuming that's the only field you want to save in your users table, almost. Make sure that you wrap $per_user_salt in quotes (single or double) as your hash is a string (i.e. INSERT INTO users (per_user_salt) VALUES ('$per_user_salt').

Why do you store the 'per user salt'? Wouldn't it be better to make an algorithm that depends on data already present in the database, which makes it less obvious which salt was used? It's not a requirement in any way, but it might make your passwords a little more secure.

Written by KilZone

Shouldn't you use mysql_real_escape_string() right before the database query and not at the beginning?

Written by Manhim

@manhim, correct me if im wrong, but the only part open to sql injection is the user input for 'pw', my salt and per_user_salt are generated by me... however according to @charles sprayberry, i don't even need to escape the pw there since i'm hashing it... i'm going to leave it because i needed it escaped elsewhere also...

Written by Andypandy

@kilzone, i'm not sure what you mean - i think it is an algoritham based on data in the db... the data is the per_user_salt and the algorithm is combining salt . pw . per_user_salt then hashing... if you have a better recommendation please let me know... I've never done this before..

Written by Andypandy

@Andypandy Since you are hashing it you do not need this function. The result is mostly-assured to be alpha-numerals.

Written by Manhim

@andy Well for example if you use md5($_POST['pw']) as 'salt' you have a salt that is user depending but does not have to be stored in the database. Your hash would be hash("sha512", $pw . md5($pw) . $site_salt);, which is about as secure as a random generated number (as long as you don't tell anyone your algorithm). The big upside is, that hacking your database (for example using injection) will not result in the per_user_salt being shown, as it is not stored.

Written by KilZone

@kilzone, i see what you're saying - so if I changed my $combine to $combine = $pw . $per_user_salt . $site_salt . $site_salt . $per_user_salt . $pw; that would be more secure...? or is there a simpler way to make it way more secure like $combine = $pw . $per_user_salt . $site_salt . md5($pw);...

Written by Andypandy

@andy The whole point of the 'salt' is to avoid rainbow tables to be used to de-hash something into a password, so anything you do before hashing makes it more secure. Both options you have are more secure, since the $combine becomes more complex, but I like your last option best. However, in the end it comes down to personal preference. Just remember that your salt-trick is a form of security-through-obscurity, the less people know about how you make your $combine the better. Try to come up with something uncommon, like the two you just posted and you'll be fine.

Written by KilZone

@kilzone, also one more question - what's the best way to secure the algorithm?

Written by Andypandy

Problem is that PHP does not have a 'compiled' structure for code (unless you use Zend Guard, but that is too expensive), so anyone that accuires access to your PHP server can just read the plain text version of your algorithm. Best practise is not to store your hashing code in your root (preferably the folder above the root and if that's not possible use a subfolder) and don't tell anyone that and how you are salting the passwords.

Written by KilZone

This article might be of interest: codahale.com/how-to-safely-store-a-password

Written by Sven Koschnicke

@Sven, damn I was planning to say that right now!

Written by ahmet alp balkan

Accepted Answer

Based on comments here is what I'm going to do: Change my $combine to something that is unique per user but not stored in db. So something like: $combine = $pw . md5($pw) . 'PoniesAreMagical' . $site_salt . md5($pw);, etc etc etc... Thanks for the help...

So - for those of you trying to figure out how to do this for the first time (like me)... its all about the algorithm... make something obscure, unique, difficult to figure out; because if someone wants to get into your system, they are going to have to figure this out. Thanks to all for awesome comments.

Written by Andypandy
This page was build to provide you fast access to the question and the direct accepted answer.
The content is written by members of the stackoverflow.com community.
It is licensed under cc-wiki