When storing user's passwords that you need to verify against (but not use as plaintext) the current state of the art is:
- Hash the password
- Use a salt
- Use a slow hash function - bcrypt, scrypt, etc.
This provides the best possible protection against an attacker who has stolen the password database. It does not solve other issues like phishing, malware, password re-use, etc.
But there is one remaining problem: the slow hash function can allow a denial of service attack. A single request burns a lot of CPU, which makes a DOS possible with a relatively small number of concurrent requests, making it difficult to use defences like IP throttling.
- The client needs to fetch the salt from the server. This introduces latency on login and, unless care is taken, can reveal whether a particular user account exists.
- If hashing is done purely on the client then the benefits of storing hashes are lost. At attacker who has stolen the password hashes can simply login using the hashes.
However, I think there are acceptable solutions to both of those problems:
- The salt can be generated as hash(server_salt + user_name) - where server_salt is a random number that is unique to the server, public, and the same for all users. The resulting hash appears to have the required properties of a salt.
- The server should do a single, fast, hash operation on the hash it receives. As an example: the server stores SHA-256(bcrypt(salt, password)). The client sends bcrypt(salt, password) then the server applies SHA-256 and checks the hash. This does NOT allow an attacker to conduct a fast offline brute force attack. They can do a fast brute force of SHA-256(password) because password has a limited amount of entropy - 2^50 or 2^60 or so. But a 128-bit bcrypt(salt, password) has entropy or 2^128, so they cannot readily brute force it.
So, is this a reasonable and secure approach?
I am aware of the general advice to "don't roll your own crypto". However, in this case, I am attempting to solve a problem that is not solved by off-the-shelf crypto. For some basic credibility, this has been looked at by John Steven (a recognised expert in the field) with positive outcome from a "brief" analysis.
bcrypt(password)right? (in your solution paragraph no. 2) Feel I'd better ask even if I feel fairly certain
bcrypt(salt, password)) that they can send to the server to authenticate. To a large extent this amounts to the same thing.