5 ms·
From previous discussions about this topic, I had noted down the following best practices: Passwords should be scrypt'ed on client, and then, the server should
by sinatra 11y ago
From previous discussions about this topic, I had noted down the following best practices:
Passwords should be scrypt'ed on client, and then, the server should generate a SHA256 hash of the scrypt'ed hash and store that in DB.
- Running CPU & memory heavy scrypt hashing on the client side will allow us to use bigger hashing work-loads.
- EDIT: Removing the MITM point, because as many said, that's the job of TLS anyway.
- External brute force attackers will have to take the burden of heavy hashing. No DOSing through scrypt.
- Storing SHA256 hash instead of scrypt hash on DB means even if DB is stolen, attackers can't use stolen scrypt hashes to authenticate any client.
I would love to get others' feedback on this. EDIT: Found the reference: https://news.ycombinator.com/item?id=9305504 https://news.ycombinator.com/item?id=9305504
- vincentdm 11y agoVery interesting. Is there a reference implementation or discussion you can link to?
- sinatra 11y agoI'll try to find the discussion. EDIT: Here's the discussion - https://news.ycombinator.com/item?id=9305504 https://news.ycombinator.com/item?id=9305504
- sarciszewski 11y agoHow are you going to calculate the scrypt hash, client-side? Doesn't that scrypt hash then become the password, from the server-side application's perspective? How are you storing the salt for the user if your server only knows about a SHA-256 hash. > MITM attacks won't get access to unencrypted fields. That's TLS's job. If you, for example, are building a web app and you're delivering Javascript to perform the scrypt calculation, a MitM can replace the code to exfiltrate the user's plaintext password. It doesn't make sense for the threat model.
- sinatra 11y agoVery valid questions. Let me try to answer them and let's see if those answers are valid or not. Yes, the scrypt hash just becomes the password for the server. However, this password is going to be unique and almost impossible to guess. Salting this password on server side doesn't give us any additional benefits. The server can store the salt that the client used, though. Yes, the MITM point was minor. Just another minor security benefit on top of TLS (which takes the majority of the burden of securing against it). So, maybe I shouldn't even mention this point.
- owenmarshall 11y ago>Yes, the scrypt hash just becomes the password for the server. However, this password is going to be unique and almost impossible to guess. Salting this password on server side doesn't give us any additional benefits. I don't even your threat model. Can you walk us through how you see this working? Client takes 'crappypassword' as input, sends p = scrypt('crappypassword') The server stores SHA256(p)? EDIT: misread what you said. is this correct?
- sinatra 11y agoYes, now it's correct.
- AstralStorm 11y agoAnd 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 be stolen.
- timv 11y agoNote: 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.
- dudus 11y agoI learned very early on to never trust the client. An infected machine cold just not encrypt the password and now you have a database where infected clients just got sha256. That is if course easily broken with brute force or even rainbow tables.
- deleted 11y ago[deleted]
- joveian 11y agoAn infected machine would more likely steal the password, then still run the scrypt. Why make it easier for someone else to steal it too?
- owenmarshall 11y ago> MITM attacks won't get access to unencrypted fields. A MITM would let you hijack the JS that controls scrypt/SHA-256, so you're already at game over. You've got to deliver that to the user in some fashion (TLS!); this isn't a real win for your approach. > External brute force attackers will have to take the burden of heavy hashing. If the attacker is trying targeted access to a site the only thing that's relevant is the time they have to expend - the hash is opaque. If they have the hash from, say, a DB theft, they're already going to have to take that burden. Your approach doesn't seem to add anything. > Storing SHA256 hash instead of scrypt hash on DB means even if DB is stolen, attackers can't use stolen scrypt hashes to authenticate any client. I'm not sure what that means. If you steal my scrypt hash for example.net, how do you use that to authenticate me to example.net? Your approach pushes out complexity to the clients and doesn't seem to win us anything.
- nkrisc 11y agoYou're putting a lot of faith in the client.