4 ms·
What's the reason behind bcrypt(userId + username + password) rather than just bcrypt(password) ?
by philippta 2y ago
What's the reason behind bcrypt(userId + username + password) rather than just bcrypt(password) ?
- ReptileMan 2y agorainbow tables I guess
- Tade0 2y agoWhat if two different users have the same password?
- magicalhippo 2y agoBcrypt is salted[1], so that shouldn't matter? [1]: https://en.wikipedia.org/wiki/Bcrypt#Description https://en.wikipedia.org/wiki/Bcrypt#Description
- Tade0 2y agoAre you sure? bcrypt stores the salt and retrieves it for comparison - otherwise you wouldn't be able to generate a matching hash. Consider the case where a user has a very long username and sets their password to their userId + username + password thus recreating the scenario which lead to the incident.
- magicalhippo 2y agoThat was not my point. My point was there wouldn't be a hash collision just by two users with the same password due to the salting.
- Tade0 2y agoThere's no hash collision here, just two different hashes, each with its own salt, matching the same original phrase. If you use only the password to generate the cache key, then this password will match regardless of salt, so users with the same password will generate a cache key matching that password.
- magicalhippo 2y agoYes, that's what I pointed out when you suggested there would be a problem with two different users having the same password.
- Tade0 2y agoI'm getting the feeling that there's some kind of miscommunication here. If only the password is used to generate the hash then that password, when used to match against a previously stored hash(cache key here), will also match it, thus producing the exact same vulnerability, but worse because it's enough to have the same password as someone else. Salting does not help here at all.
- magicalhippo 2y agoThe whole point of salting is to avoid exactly that scenario, and, as I linked to, bcrypt requires salt. So when you read "bcrypt(password)", that just means the salt is implicit, not that it isn't salted.
- Tade0 2y agoThe the output of `bcrypt(password)` is: $2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW \__/\/ \____________________/\_____________________________/ Alg Cost Salt Hash The Salt part is randomly generated. When you call `bcrypt.compare(output, password)` it uses the salt that's contained in `output`. Two calls of `bcrypt(password)` will generate different outputs(so different salts and thus different hashes), but still if you run `bcrypt.compare(output1, password)` and `bcrypt.compare(output2, password)` they will both match as long `password` was used to generate both. In short: you can't use just the password as that's going to match a cache key that was generated by whoever typed in this exact password. The salt is only there to prevent offline attacks.
- magicalhippo 2y agoBut if you're using bcrypt to compute a dictionary lookup key, you're not going to use bcrypt.compare as it would require a linear scan and be slow as a snail. Rather you use the bcrypt output itself as the lookup key. And if you do that then the salt will indeed do what it's designed to do. The function you used is a convenience function which generates random salt, but you can specify your own as is done in this[1] illustration of the Okta incident. What bcrypt.compare does is essentially to extract the salt from the provided previous output, compute new hash using that and the provided password, and check that the old and new hashes matches. As such it's equivalent to comparing the outputs of two different "runs" where the same salt is used (modulo timing attacks). So if you need to recompute the lookup key then you need to use the same salt value. [1]: https://kondukto.io/blog/okta-vulnerability-bcrypt-auth https://kondukto.io/blog/okta-vulnerability-bcrypt-auth
- johnisgood 2y agoWhy would that matter though?