This probably is a duplicate question. But I seem to keep seeing people recommend hashing passwords client-side while ignoring the true complexity of the issue and the near impossibility that anyone other than an information security scientist is going to get it right.
Bottom line, if you're making a web or mobile app, use HTTPS, configure it correctly and hash passwords on the server. Use bcrypt or scrypt, or if it's the easiest library for you to use, use pbkdf2. Those libraries are well designed. You're not going to invent better. BUT; if you use them to hash the password on the client, then send the hash, then you just made the hash your password. And if you're a mobile app developer, don't you dare set the flag in your HTTPS setup that tells it to skip checking the certificate chain.
It's dang complicated
Occasionally people mention using nonces, etc. Pass-the-hash, challenge-response authentication is nothing new. And various half-baked pass-the-hash schemes have been broken more than once. Consider Microsoft Lan Manager: LM, NTLM and NTLM with session security are all broken. NTLMv2 is apparently still secure, but it's the fourth in the chain. Microsoft has a few resources to throw at the problem. You're going to do better on your own? Kerberos is an example of a solidly secure authentication and authorization system with a lot of science behind it, which generates tickets and applies nonces and passes those around instead of transmitting the passwords.
But Kerberos is quite complex, and relies on computers having trust relationships with each other, and on computer clocks being in sync. It's complicated.
Half-baked attempts to pull off something similar between a web browser and web server, unless you're using the actual Kerberos protocol supplied by a competent, well-vetted vendor, are bound to end in tears.
Security is complicated, subtle and hard.
HTTPS is pretty darn good
Perfect? Maybe not, but current versions aren't broken. If the server is using a strong certificate (2048 bit key) and strong cryptography (TLS 1.x or greater), it's pretty darn solid. Sending your password via HTTPS is not the same as passing it in plain text.
Users should not use the same password for multiple sites
Really, seriously, if they do, it's ultimately on them. They've been warned so many times now. Even the Today Show anchors know not to use the same password on multiple sites now, for crying out loud.
Don't make the hash the actual password, believing you have implemented security
If you just hash the password on the client side and store that value in the database for comparison, then the hash itself is the password. Period.
Are you going to build a full challenge-response pass-the-hash system using nonces, and do it without introducing fatal bugs? Do you really have the time, budget and expertise for that?
There may still be a benefit for the user to hash their password before sending it. If the hash is intercepted, the attacker couldn't use it to log in to OTHER sites.
However; if that is done, and you don't have the chops to create the actual equivalent of Kerberos or NTLMv2 just for your app, it should be done completely independent of anything the server does or expects.
The server must compute the hash
Given all the preceding, the server still needs to hash whatever is passed to it (call it a hash, call it a password, same thing in this context), with salt that is stored on the server, completely blind to anything the client is doing.
In other words, if the client is sending a hash, great, but the server doesn't know or care. It's just a password.
You're not trying to prove that the client knows the hash value. You're trying to prove that the client knows the original secret (aka "the password").
So the server hashes the incoming password fresh each time, using salt that is stored on the server, and compares the computed hash to the stored hash. If they match, authentication has succeeded. Otherwise, authentication fails.
So very many things can go wrong if you try to be clever
You're going to get it wrong. You just are.
Imagine this example:
- Your client hashes passwords
- Your server stores said hashed passwords
- Attacker social engineers your CEO and steals your account database
- Attacker has a database full of passwords, not hashes, but actual passwords to actual accounts on your system.
Part of my point, I guess, is that the very question "Should I hash on the client or the server" belies the true complexity of the issue and far too many answers either fail to address the complexity at all, or gloss over it in ways that make a system less safe, not safer.