Hacker News new | ask | show | jobs
by CiPHPerCoder 3670 days ago
That question should never even need to be asked. The library you're using should take care of that for you.

In PHP:

    $storeMe = password_hash($plaintext, PASSWORD_DEFAULT);
    if (password_verify($plaintext, $storeMe)) {
        // Logged in
    }
The detail is totally abstracted away. All sane password hashing libraries offer this API.

See: https://paragonie.com/blog/2016/02/how-safely-store-password...

EDIT - CANNOT REPLY:

  > One major failure of this article:
  >
  > You should generate a random salt for each user and store it alongside the user
  > record in the DB.
No, you shouldn't. Your library should do that for you, and store it as a single string that's opaque to the developer.

  > I completely disagree. This implies that my DB ORM handles password stuff,
  > which doesn't make sense.
See the passlib section: https://paragonie.com/blog/2016/02/how-safely-store-password...
3 comments

One major failure of this article:

You should generate a random salt for each user and store it alongside the user record in the DB.

How is this a failure? That's correct. (If your password hashing library doesn't handle this automatically, of course. But it does the same internally.)
Is it normal for password hashing libraries to save salts to a database?
Yes, they usually produce a string that looks something like "salt||hash". (Salt is a non-secret value.)

This result of bcrypt:

   $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
    |/ \| \____________________/\_____________________________/
    |   |        salt                      hash
    |  cost 
    |
 algorithm,
  version

You store this string in the database.
The big thing about this, is that it is perfectly "OK" to store both the algorithm, cost, and salt alongside the hash.

Most people seem to think, and myself included when I was new-to-it, that storing all those things together would compromise the security. The point of the hash is that it is impossible (almost) to get to the hash without the user's password, and there is no way to get to the password with the entire string you posted.

I'm naive about these things, but I was under the impression that salt just thwarted pre-computed hash tables? I guess should be "just" in quotes.

So somebody with resources and motive could still brute-force that string. It seems that storing the salt somewhere else would add a comparable amount of security as the salt itself. It seems prudent along the lines of "don't put all your eggs in one basket."

Rather than expecting the password hash library to store something into your application DB, you should be managing the access to that DB yourself.

In our case, we use an immutable attribute of each user as their hash. This might be an internal identifier, or the timestamp on which their account was created, or something like that.

Rather than expecting the password hash library to store something into your application DB, you should be managing the access to that DB yourself.

You do manage it yourself. Password hashing library doesn't access your database, it produces a string that you store, which includes salt and password hash.

In our case, we use an immutable attribute of each user as their hash

What? You really need to talk to security-competent people.

> In our case, we use an immutable attribute of each user as their hash.

I assume you mean "as their salt". And even then, why the half-measure? Just laziness? Sure, a guessable/computable salt is better than no salt, but it's not nearly as good as a random salt.

I assume you mean "as their salt"

Yes, thanks for clarifying what I meant to type.

why the half-measure? Just laziness? Sure, a guessable/computable salt is better than no salt, but it's not nearly as good as a random salt.

But isn't the salt essentially safe to make public anyway? That being the case, how does it matter what value you use, so long as it differs between users?

Ideal salt is a large (e.g. 16 bytes or more) random byte string generated for each password.

If there's a reason for it (in most cases, there is none), some trade offs are possible, e.g.:

Salt is a large random string unique per user, not per password.

Given two hashes of passwords for the same user it reveals whether passwords are the same.

Salt is a small random string or some predictable value.

Attackers can precompute guesses and then look them up.

If you use some immutable identifier per user as salt, both of these attacks are possible. Is there a reason for this? Since you already store password hash in your database, I'm 100% certain that it's not, you can generate large random salt per each password hash and store it.

As for "safe to make public": there are many things in crypto called "public" where "public" doesn't mean that the whole world is free to get it, but instead means an opposite of "private", or, as I like to call them, "non-secret". Yes, salt can be made public, but shouldn't (unless there's a reason for it — like in a kind of client-side crypto where server stores salt and sends it to clients) to avoid precomputation.

It being unique goes most of the way, you're right (though hopefully it actually is unique!). I was being dramatic when I said "not nearly as good". But making the salt easily guessable does allow an attacker to precompute rainbow tables, etc. So if there was a breach and an attacker got a dump of your password hashes, it might mean the difference between you having time to invalidate those passwords or not.

Good look at the issue here: http://security.stackexchange.com/questions/41617/do-salts-h...

But then you are using php so you already lost.
If there was any truth at all in that claim, you should be able to compromise paragonie.com right now simply for it running PHP.

Otherwise, that claim is false.

> No, you shouldn't. Your library should do that for you, and store it as a single string that's opaque to the developer.

I completely disagree. This implies that my DB ORM handles password stuff, which doesn't make sense.

Python 3 example:

Syntax: hashlib.pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None)

Example:

>>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000)

>>> binascii.hexlify(dk)

b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'

Extremely simple and safe to use. Trivial to store and save/retrieve the salt from DB.

I'm not too familiar with this library, but on inspection this approach seems to have a couple of drawbacks that libraries like bcrypt solve for you:

1) You need to store the salt alongside the password.

2) If you want to futureproof the stretching factor (e.g. change from 100000 to 1000000), you need to store that alongside the password hash as well.

3) If you want to futureproof the hashing algorithm, you need to store that alongside the password hash.

The value of the *crypt solutions is that they store the input parameters as part of the stored secret. So you can make adjustments later on without invalidating existing stored passwords, or having to resort to annoying "double-hashes" to migrate to a new approach.

I don't understand your comment about the ORM needing to handle passwords. It's a simple fetch of a field from the DB, which you then pass as an input to your password validator. How is that any harder than fetching a salt and a hash and passing those to your validator?

I did not realize that the hash and salt are concatenated