Live data from Hacker News

How to Safely Store Your Users' Passwords in 2016

paragonie.com

171–180 of 321 posts

Re: How to Safely Store Your Users' Passwords in 2016

#171

Earlier quoted context omitted.

Crackable in what way? Of course the core of it could be upgraded, but the idea is sound. Sounds like you could say the same thing about using a DES-based hash. "Don't Hash! It's weak!" is throwing the baby out with the bath water.

In exactly the same way as any other password hash is cracked.

By iterating over all passwords? That seems like the definition of a good password storage if that's the only way! I mean, you can make the same complaint against anything; it's meaningless by definition.

Sure, public-private pairs are more difficult (to impossible) to brute force once they're so long, but srp, bcrypt, pbkdf2 &c are pretty good when you want/need a password. Srp being superior in that your secret never leaves your computer.

Re: How to Safely Store Your Users' Passwords in 2016

#172

I believe the Ruby example is incorrect: When checking a password's validity, you must use a constant-time comparison or else you are exposing a vulnerability to side-channel timing attacks. There is an open issue in Coda Hale's bcrypt repo about this: https://github.com/codahale/bcrypt-ruby/pull/119 My stance on posting "best practice" articles is: you must follow all best practices in them.

As mentioned elsewhere in the thread, this isn't a "you must", this is a "you might as well".

Timing attacks depend on an attacker having control over the hash being compared (e.g. they have a HMAC in a cookie they're sending you, and they can adjust it character by character) - with randomised secret salts and server-side hashing, this isn't the case.

The SCrypt example is the one I'm more concerned with. The defaults there are 1MB of RAM and 64-bit salts, both of which could do with increasing. I have an open issue on this: https://github.com/pbhogan/scrypt/issues/25

As it is, the example would probably be better as this:

    password = SCrypt::Password.create(usersPassword, salt_size: 32, max_mem: 16*1024*1024)
You'll be pleased to know SCrypt::Password#== is at least constant-time.

Re: How to Safely Store Your Users' Passwords in 2016

#173

Earlier quoted context omitted.

Yes, now it's correct.

And still invalid. Are you assuming that collisions against SHA256(bcrypt(p)) are harder than SHA256(p), right? Any math to prove that? Otherwise, you're relying on the user side to properly safeguard bcrypted password. That is often wrong. You cannot store any kind of transformed password anywhere, or it's no longer a password, but a token. Yes, those "Remember me" things transform passwords into tokens. Tokens can…

Note: I'm not endorsing the client-side scrypt/bcrypt approach, but I do think it's interesting.

I'm going to refer to bcrypt because that's what your comment used, but the parent post used scrypt.

> Are you assuming that collisions against SHA256(bcrypt(p)) are harder than SHA256(p), right?

I don't think it is. I think it's assuming 2 things:

1. That SHA256 collisions are rare enough, and SHA256 attacks are hard enough, that they can be ignored.

2. That the output space of bcrypt is large enough to overcome the risk that salting is usually designed to overcome.

On the first point: This approach simply isn't worried about SHA256 collisions between passwords. Yes, it's theoretically possible that 2 users with different passwords and/or different salts might end up with the same hash. If that happened often then it would be an issue - if you had n distinct users in your system but only n/2 distinct hash values, then if an attacker had a copy of your password store, it would effectively double the pay-out each time they successfully cracked a user's password (that is, each cracked password would allow them to authenticate as 2 users).

But in practical terms, collisions are going to be tiny, and you're really worrying about the case where n distinct users have n-1 or n-2 distinct hashes. That's not going to meaningfully change your exposure.

What is more of a risk (and this might be the point you were making) is that if any of your hashes happen to collide with the hash of a known input, then you're screwed, and while that's unlikely, "unlikely" isn't an ideal protection.

When you're storing { SALT , HASH( SALT || INPUT) } you're reasonably protected against such collisions because they would only be effective if the known input happened to start with the salt.

What the bcrypt approach can offer is that it knows that the input to SHA256 needs to be the output of bcrypt, so you can refuse to accept anything that isn't 186 bits long (or 31 base64 characters, depending on your approach). That constraint might well be stronger protection than a salt, although I haven't run any numbers.

Probably adding a salt is safer, and I was going to attempt serious analysis on this scheme I'd certainly want to test whether that was true or not.

On the second point, salting is usually designed to work around the scenario where 2 users have the same password and therefore (absent a salt) would have the same hash. It is not specifically intended for the scenario (described above) where two users have different passwords that happen to hash to the same thing.

In the approach discussed here, the input to the hash is the output from bcrypt. That value has already had a salt applied, so 2 users with the same original passwords would be providing different inputs to our hash function, so we would be storing different outputs.

> you're relying on the user side to properly safeguard bcrypted password

I think that's a genuine issue. You need to do a not-insignificant level of client-side processing on the user's password. You're relying on the browser disposing of that data securely. It's "just bits in RAM", but bits in RAM leak, and there's no way for the browser to know that the bits you were working with were sensitive.

Re: How to Safely Store Your Users' Passwords in 2016

#174

I called my bank the other day and they asked over the phone for my password. This isn't a bank I often use, I only currently have a loan through them so I've never used the login on the website. I said I don't remember setting a password. They gave me a hint about the characters in the password and I was able to remember the password based on their hint. I verbally said the password character by character and they c…

Same thing happened to me, my local credit union emailed me my password. They ensured me that they use "bank-level encryption". Of course I didn't get into the difference between one- and two-way encryption with the teller, or that email isn't secure. We live in an age where this should be unacceptable. Why aren't there financial security laws yet?

[deleted]

Re: How to Safely Store Your Users' Passwords in 2016

#175

Earlier quoted context omitted.

I feel that this is needlessly dangerous, personally. How are the salts managed? This detail is important. SHA256(scrypt(password, constant_value_instead_of_salt)) is going to produce collisions in the stored hash.

I think he's going for SHA256(scrypt(password, salt, work_factor)) and saying the bare SHA256 is sufficient. As opposed to SHA256(salt+scrypt(password, salt, work_factor)). I think it's dangerous because of the dependence on the client, and useless because scrypt(password,salt,work_factor) on the server is plenty hard to attack.

> scrypt(password,salt,work_factor) on the server is plenty hard to attack

For a large enough work_factor. In practice "large enough" is usually interpreted to mean "something that seems safe without being so large that I need to buy lots more servers"

The argument (which I'm interested in, but not yet sold on) is that moving the scrypt to the client allows you to pump up the work_factor even higher than you would have been willing to do on the server.

Re: How to Safely Store Your Users' Passwords in 2016

#176

Serious question: What about using a Public/Private key encryption to store the password? - Private key is stored in a secure place. Offline for all i care; printed on a piece of paper; memorized and swallowed. - When user creates the account - password is padded with salt, then a public key is used to encrypt it. The resulting encrypted form is stored, along with the salt. - When user attempts to authenticate - the…

Because it would leak information about the length of the password (and would require length limitations on passwords if the encrypted password is stored in a database). More importantly, I don't see what benefit you get from encrypting your password (read: slow and causes the above issues) rather than using hashing algorithms. If you use the crypt standard for storing your hashes, you can also update the hashes on login when migrating to a new algorithm. Unix systems have solved the "storing passwords" problem. We just need to keep iterating on "what hashing algorithm is trending on HN this week".

Re: How to Safely Store Your Users' Passwords in 2016

#178

Bad idea to use bcrypt.hashSync in Node.js. I hate that so many tutorials use that one instead of the correct bcrypt.hash with a callback. This is Node.js for that 200 ms where you are hashing that password nothing else runs, no requests, everything stops. Here is the correct way to use bcrypt in Node.js: bcrypt.genSalt(10, function(err, salt) { if (err) return; //handle error bcrypt.hash(clearPassword, salt, functio…

More specifically, any functions that end in Sync should be avoided.

Unfortunately a lot of people think that these functions are a simple way to "not have to deal with callbacks", which is not correct...

Re: How to Safely Store Your Users' Passwords in 2016

#179

Bad idea to use bcrypt.hashSync in Node.js. I hate that so many tutorials use that one instead of the correct bcrypt.hash with a callback. This is Node.js for that 200 ms where you are hashing that password nothing else runs, no requests, everything stops. Here is the correct way to use bcrypt in Node.js: bcrypt.genSalt(10, function(err, salt) { if (err) return; //handle error bcrypt.hash(clearPassword, salt, functio…

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

How does that look now?

Post reply on HN