While I hope never to make the mistake, is it viable to do an unsalted hash on the front end and send that to the back end instead? Should the same or similar mistake ever be made, at the very least it's not a plain-text password as the real password was never even sent in the first place, but the back end will still use bcrypt to salt, hash, and store the password securely?
Yes, you can do that. However, it will not earn much in terms of security. Why? Because it just means that as far as the attacker is concerned, the hash that client sends is the password.
That is, if somehow the database is leaked, the attacker does not have to figure out the original plain text password, instead it only has to figure out the hash that was send to the server. Why? Because when attacker modifies the front end or creates a rogue client to attack the server, it will simply send the hashes instead of passwords.
For abstract, the attacker does not need the original plain text password at all.
While I understand an unsalted hash isn't particular strong, if in the scenario of a mis-configuration which does somehow log or by any other means store the unhashed password, at least a SHA512 hashed password is stored rather than a plain-text password?
Yeah, and that is all that the attacker needs. Edit: well, that, and to mess a little with the client side code. Since we are assuming HTTPS, I'll assume we are on a browser, so that messing with the client side code entails using the developer tools of the browser.
There are some situations where it could make sense to do cryptography on the client side, this is not one.
The only thing that you arguably won is that the attacker who already successful stole the hash and was able to compromise the account of a user, probably won't be able to reuse it to enter other services where the user has an account...
... I repeat, once everything was screwed, perhaps you earn a little something...
... As you would know, this is not a correct solution for that problem. Which is evidenced by the fact that if everybody did the same client side hash thing, then the attacker would be able to reuse those hashes.
Thus, if the user has different passwords for different services, you approach earns nothing.
Addendum: What if you wanted to defend the user from the administrators?
Note: I will be using the word "protected" to mean that some form of cryptography was used to cipher it.
We often talk about a database being stolen or otherwise compromised. Meanwhile an administrator could just get in and change the stored hash for a user, and get access that way. It could be reverted before the user gets back. And with full privileges that could be done without trace.
There is also the code. The password was at some moment in plain text in the server before being hashed. Depending on the platform, it could be easy to inject some code to steal the passwords there.
And besides all of that, the administrator have access to the rest of the data about the users anyway.
Here is a way...
On account creation (on the client):
- Generate an asymmetric key pair.
- Derive a key from the password for symmetric cryptography.
- Cipher the private key (from step 1) with the symmetric key (from step 2)
- Send to the server the public key (from step 1), and the protected private key (from step 3).
On log in (on the client):
- Derive the key from the password again.
- Get the protected private key from the server.
- Decipher the key (from step 2) with the derived key (from step 1)
This means that the server can cipher messages to be read only by that user. Furthermore, if these messages are created on another client, they were never in plain text on the server. The administrators would not be able to read them, because the private key is protected under a key that was never on the server either.
We can add a second, or even more symmetric keys protected under the asymmetric one for performance, we could also use a protocol for perfect forward secrecy. See also Diffie-Hellman. I'm keeping it simple here.
You may consider combining this with a traditional login system, however you should not send the password in plain, because if you do, then it would be possible to derive the same symmetric key on the server. Here, doing a hash on the password before sending it could be useful.
However, that it could be tricky to show that the combination of hash and key derivation algorithm is secure when used this way. Edit: stick to the recommended algorithms at the time.
There is an alternative: challenge based authentication. If the client has the private key, then the client can sign a message in such way that it can be verified by the public key that the server has. In this case, to authenticate the server would send a random text challenge to be signed, and the server verifies that the client did sign with a key matching the public key stored on the server. This way, the password was never on the server at all.
Note: for the above authentication method to be secure I am assuming it happens over HTTPS.
Stolen database? As far as passwords are concerned, there are no passwords there, they never were there.
This has a few drawbacks:
- Many systems need the data in clear to work, meaning you would hardly be able to put all the data under a key.
- It is slow for the user, as a lot of cryptography is happening client side.
- If the user forgot their password, the access to the private key is lost too. The server can let you set a new password, and even a generate a new key pair, but it will not be able to access data that was protected under the old key.
Does somebody use this?
Yes: Famously MEGA.nz does basically this. WhatsApp does something very similar (except they do not store the messages, you do). Other similar products that feature “End-to-end encryption” have similar solutions.