Okta released a security advisory 4 days ago, stating that accounts with username longer than 52 characters can login with arbitrary password under specific conditions.
Some people in X/Twitter suspect that Okta use userid + username + password
as the input of bcrypt.
If this is true, then the password would be ignored by bcrypt given a long enough userid + username
.
A commenter suggested pre-hashing the input with SHA256 before applying bcrypt, thus avoiding the length limit problem. This pre-hash method is also mentioned (and generally approved) in some answers in this site (1,2).
However, the OWASP cheatsheet explicitly discourage this:
An alternative approach is to pre-hash the user-supplied password with a fast algorithm such as SHA-256, and then to hash the resulting hash with bcrypt (i.e.,
bcrypt(base64(hmac-sha256(data:$password, key:$pepper)), $salt, $cost)
). This is a dangerous (but common) practice that should be avoided due to password shucking and other issues when combining bcrypt with other hash functions.
I am not a security expert, so I am looking for professional opinions:
- Should I strictly avoid pre-hashing bcrypt input with another hash function, as mentioned in the OWASP cheatsheet?
- Would I be in serious trouble (e.g. passwords easily cracked) if I pre-hash bcrypt input with SHA256?
- Someone on Reddit suggested that salting the sha256 hash BEFORE applying bcrypt can prevent password shucking (at least this is how I read it). Is this true?
Edit: I have a follow up question.
- This blog post (which is cited in the OWASP cheatsheet excerpt above) mentioned that it is safe if we encode the prehash first (with base64 or hex) before throwing it to bcrypt. I understand this is to eliminate null bytes from the raw output.
However, OWASP used bcrypt(base64(hmac-sha256(data:$password, key:$pepper)), $salt, $cost)
as an example, which implies it is unsafe even if you encode the prehash output.
Are they in conflict whith each other? If yes, which one is correct?
base64
. I think there's a problem in the wording of the OWASP page, it should warn of the issue and point to the right fix (like using the base64 version as described in the example).bcrypt(somehash(pass))
from the get go, right?somehash(pass)
can leak through an entirely different application which isn’t under your control and which you may not even be aware of. So this is not just about old hashes in your own application. The only way to prevent the attack is use a parameterized inner construct like HMAC which accepts both a key/salt and the password, and to not hash existing hashes (since the current ones may have been leaked at some point).