However, lest anyone get the wrong opinion, password hashing is a very simple, straightforward, solved problem and has been for years.
One person doing something monumentally stupid doesn't make Auth some kind of cryptic minefield.
However, lest anyone get the wrong opinion, password hashing is a very simple, straightforward, solved problem and has been for years.
One person doing something monumentally stupid doesn't make Auth some kind of cryptic minefield.
I would wager that most people reading this, if earnestly asked by a coworker "do you think it's fine for me to hash a password before passing it to bcrypt? I want to be able to support passwords over 72 characters and bcrypt truncates its input." would answer something along the lines of "I don't see how it could hurt" rather than "that's dangerous because a binary hash would result in a large portion of the passwords being hashed as an empty string"
The engineers that originally implemented and reviewed this were not idiots, they just weren't security experts.
Try asking the following question on Twitter:
"While passing binary data, which example is safer for storing passwords?
[ ] $password | sha256 | bcrypt
[ ] $password | bcrypt"
What do you think the average programmer would say? Most would probably say they are either equal, or the first one, without knowing this specific thing, because most people don't implement their own password-hashing, they use library/framework provided ways that has been established as best practice already.
But, can't blame them really, the difference is marginal and innocent on the surface, but once you understand the implementation, you'll see the holes.
The yearly report of leaks in Fortune 500 companies should be proof enough of this.
EDIT: To elaborate. Crypto scheme is only one tiny facet of a successful authentication solution. Where do you store the hash? What language and stack are you using? What is the maturity of libraries available to you? What protocols? And many more seemingly tiny decisions. All it takes is a lazy developer that imports an insecure transient dependency or snoozes on a CVE.