phdphd Posted July 1, 2016 Share Posted July 1, 2016 Hi All,I guess that people who developed password_hash did it with salt uniqueness in mind. However is it possible that two users defining the same password get the same "hash-salted" version of it ? If so, how to prevent this situation?Thanks. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/ Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 Possible? probably, and I mean that in the "anything's possible" kind of way. Likely to happen in the real world? No, unless for some crazy crazy reason you use a static salt for all passwords) How to prevent it? Why would you bother? Even if it were to happen, what harm do you envisage? Technically you could put a unique index on the DB column and then request the user try a different password if it throws a duplicate entry error (just don't tell the user why their password doesn't work!). But the chances of the same random salt being generated for the same password the one time another user registers it is infinitesimal (like one times ten to the minus several billion). Of course enforcing a good password requirement will reduce the chance of raw password collisions as well. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534159 Share on other sites More sharing options...
phdphd Posted July 1, 2016 Author Share Posted July 1, 2016 Thanks, Muddy_Funster. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534161 Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 Quite welcome. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534163 Share on other sites More sharing options...
requinix Posted July 1, 2016 Share Posted July 1, 2016 If so, how to prevent this situation?Don't do anything. The only thing you should ever do with a password is make sure it is "secure enough": letters, numbers, symbols, minimum length, not a common password, doesn't contain their username, that stuff. The odds of two users picking the same password and getting the same salt are astronomical and, most importantly, it doesn't matter if it happens. (Would be cool to see, though.) in b4 jacques 1 Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534164 Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 @requinix I'd like to see the numbers on how many users it would take to guarantee a duplicate hash assuming every one used the same password. Also I like using phrases for passwords over actual words eg. "I used to live at 221b Bakers Street, but got fed up with Danger Mouse ruining all the letters I put in the post box" would be a good one Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534166 Share on other sites More sharing options...
Jacques1 Posted July 1, 2016 Share Posted July 1, 2016 @requinix I'd like to see the numbers on how many users it would take to guarantee a duplicate hash assuming every one used the same password. A collision probability of 0.5 would require ~2.2E19 users (see birthday attack). Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534167 Share on other sites More sharing options...
phdphd Posted July 1, 2016 Author Share Posted July 1, 2016 Not so much related with the above subject/comments, but might be interesting to know; I have been playing with an online php editor (http://sandbox.onlinephpfunctions.com/). $string='hel$lo'; echo 'string is '.$string."\n";//displays "string is hel$lo" echo password_hash($string, PASSWORD_DEFAULT)."\n"; is ok, while $string="hel$lo"; echo 'string is '.$string."\n";//displays "string is hel" echo password_hash($string, PASSWORD_DEFAULT)."\n"; would still generate a hash, but also an "Undefined variable: lo" warning, apparently due to double quotes. Actually only "hel" is taken into account. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534168 Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 double quotes create what I call "loose" stings, any PHP special chars - such as $ are parsed as code whilst within the string. single quotes make absolute strings, so everything inside them is taken as a part of the string literal (with the exception of the escape character). see here for more detailed info on PHP strings. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534169 Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 @Jacques1 : thanks for the link, though I'd be lying if I said I understood half of the formula on that page. It doesn't look like the answer to what I was asking though. Assuming URANDOM is being used to create the salt, how many times would the same password have to be put trough the same algorithm in order to guarantee a collision? Is that what you answered? Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534170 Share on other sites More sharing options...
Jacques1 Posted July 1, 2016 Share Posted July 1, 2016 Is that what you answered? A random number generator doesn't guarentee anything – except the trivial fact that you're guaranteed to get duplicates when you've run out of salts. If that's what you wanted to know, the answer is 2^128 + 1 (the number of possible 128-bit salts and one more). A much more practical problem is to actually take the randomness into account and calculate the number of required users to reach a certain duplicate probability. That's what I was referring to in my reply: To get a 50% chance of identical hashes when the salts are random and the passwords are idential, you need around 2.2E19 users. The latter number is a lot smaller and can actually be alarming for shorter salts. For example, a 64-bit salt seems astronomical as well when you look at the number of possible values (~10^19). But it only takes a few billion users to end up with a 50% chance of a collision. This may not happen in a single application, but it will certainly happen accross multiple applications. 1 Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534171 Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 Yeah, the first bit was what I was asking about. I wasn't sure what the word length of URANDOM was, so didn't know. Still 2^128+1 doesn't really register to me, so I fond this page that helps conceptualise the size of that number: http://bugcharmer.blogspot.co.uk/2012/06/how-big-is-2128.html Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534172 Share on other sites More sharing options...
Jacques1 Posted July 1, 2016 Share Posted July 1, 2016 (edited) As to the original question: While the salt isn't a problem, there are problems with the code. Do not rely on PASSWORD_DEFAULT. The whole point of modern password hash algorithms is to make the hashing as expensive as possible within the limits of your hardware. If you just go with the (low) default parameters, your hashes will be weaker than necessary. A better stratety is to choose a specific algorithm (PASSWORD_BCRYPT is the only one right now) and then increase the cost parameter until the duration is no longer acceptable. The previous value is the optimimum. Also don't hash passwords directly. The current bcrypt algorithm in particular cannot handle arbitrary input. Long passphrases (like the one by Muddy_Funster) and null bytes will lead to truncation, meaning the hash is again a lot weaker than expected. A common workaround is to pre-hash the password with another hash algorithm like SHA-256: <?php function bcrypt_hash($password, $cost) { /* * Pre-Hash the password with SHA-256 to obtain a 256-bit binary hash. Then encode the binary hash with Base64 to get a * string of 43 ASCII characters. This makes sure the string is within the length limit of bcrypt (56 bytes) and doesn't * contain any null bytes. */ $binary_prehash = hash('sha256', $password, true); $encoded_prehash = rtrim(base64_encode($binary_prehash), '='); return password_hash($encoded_prehash, PASSWORD_BCRYPT, ['cost' => $cost]); } $raw_password = 'I used to live at 221b Bakers Street, but got fed up with Danger Mouse ruining all the letters I put in the post box'; $cost = 12; // adjust this to your current hardware var_dump( bcrypt_hash($raw_password, $cost) ); --- Yeah, the first bit was what I was asking about. I wasn't sure what the word length of URANDOM was, so didn't know. 128 is the bit length of bcrypt salts. It has nothing to do with randomness. You'd have the same limit if you used sequential salts. Edited July 1, 2016 by Jacques1 Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534173 Share on other sites More sharing options...
Muddy_Funster Posted July 1, 2016 Share Posted July 1, 2016 128 is the bit length of bcrypt salts. It has nothing to do with randomness. You'd have the same limit if you used sequential salts. now your just showing off. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534177 Share on other sites More sharing options...
phdphd Posted July 1, 2016 Author Share Posted July 1, 2016 Thanks Jacques. What would be the right password_verify() syntax ? I applied your function to "hello" as password, and obtained string(60) "$2y$12$4HJ4ttxHjrmhnNamYZPftehUIlZ.IkQndxDca50kid.lmSXLjhTqy". Then I ran : $hash = '$2y$12$4HJ4ttxHjrmhnNamYZPftehUIlZ.IkQndxDca50kid.lmSXLjhTqy'; if (password_verify('hello', $hash)) { echo 'Password is valid!'; } else { echo 'Invalid password.'; } And got "Invalid password." Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534183 Share on other sites More sharing options...
Jacques1 Posted July 1, 2016 Share Posted July 1, 2016 You have to go through the exact same prehashing procedure as above. function bcrypt_verify($password, $hash) { $binary_prehash = hash('sha256', $password, true); $encoded_prehash = rtrim(base64_encode($binary_prehash), '='); return password_verify($encoded_prehash, $hash); } Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534184 Share on other sites More sharing options...
phdphd Posted July 1, 2016 Author Share Posted July 1, 2016 Thank you, Jacques! Very much appreciated (as usual ). Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534185 Share on other sites More sharing options...
phdphd Posted July 3, 2016 Author Share Posted July 3, 2016 Is it safe/necessary to run a "mysql real escape" against the result of the above bcrypt_hash($password, $cost) function before storing it in a database ? I would say yes, based on the first answer to this question. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534197 Share on other sites More sharing options...
Jacques1 Posted July 3, 2016 Share Posted July 3, 2016 As explained in the second answer, the mysql_* functions are ancient and have been removed from PHP. Manual SQL-escaping in general is deprecated, because it's far too error-prone (as you can see). Nowadays, we use PDO (or mysqli) together with prepared statements. The query string is supposed to be entirely static with no variable insertion of any kind. If you need dynamic input, you use query parameters and then bind the input to those parameters. This not only solves your current problem. It eliminates the risk of SQL injections altogether (as long as the query strings are in fact static). Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534198 Share on other sites More sharing options...
phdphd Posted July 3, 2016 Author Share Posted July 3, 2016 Thanks. Quote Link to comment https://forums.phpfreaks.com/topic/301418-password_hash-and-salt-uniquess/#findComment-1534199 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.