Why is client-side hashing of a password so uncommon?
Inventor of JavaScript password hashing here
Way back in 1998 I was building a Wiki, the first web site I'd built with a login system. There was no way I could afford hosting with SSL, but I was concerned about plaintext passwords going over the Internet. I'd read about CHAP (challenge hash authentication protocol) and realised I could implement it in JavaScript. I ended up publishing JavaScript MD5 as a standalone project and it has become the most popular open source I've developed. The wiki never got beyond alpha.
Compared to SSL it has a number of weaknesses:
- Only protects against passive eavesdropping. An active MITM can tamper with the JavaScript and disable hashing.
- Server-side hashes become password equivalents. At least in the common implementation; there are variations that avoid this.
- Captured hashes can be brute forced. It is theoretically possible to avoid this using JavaScript RSA.
I've always stated these limitations up front. I used to periodically get flamed for them. But I maintain the original principle to this day: If you've not got SSL for whatever reason, this is better than plaintext passwords. In the early 2000s a number of large providers (most notably Yahoo!) used this for logins. They believed that SSL even just for logins would have too much overhead. I think they switched to SSL just for logins in 2006, and around 2011 when Firesheep was released, most providers switched to full SSL.
So the short answer is: Client-side hashing is rare because people use SSL instead.
There are still some potential benefits of client-side hashing:
- Some software doesn't know if it will be deployed with SSL or not, so it makes some sense to include hashing. vBulletin was a common example of this.
- Server relief - with computationally expensive hashes, it makes sense for the client to do some of the work. See this question.
- Malicious admins or compromised server - client-side hashing can prevent them from seeing plaintext passwords. This is usually dismissed because they could modify the JavaScript and disable hashing. But in fairness, that action increases their chances of being detected, so there is some merit to this.
Ultimately though these benefits are minor, and add a lot of complexity - there's a real risk that you'll introduce a more serious vulnerability in your attempt to improve security. And for people who want more security than password, multi-factor authentication is a better solution.
So the second short answer is: because multi-factor authentication provides more security than client-side password hashing.
To understand this problem, first you have to understand why we hash passwords. It is completely possible to store a password in plain text on a server and simply compare the password transmitted to the password received. As long as the password is protected in transit, this is a secure means of authentication (shared secret).
The reason that passwords are hashed is because the problem isn't the authentication, but the storage. If the server is ever compromised, the attacker would immediately have access to all user accounts as they would now know the secret used for authentication of the users.
Hashing acts as a barrier to this. Since the server doesn't know the actual input required to authenticate, even a compromise to the DB does not grant an attacker access to the user accounts. They would still need to figure out the input to give to reach the hash values the application checks against. Sure they could alter all the values to something they know, but this would rapidly throw up suspicion and the system would be shut down and secured.
So, the problem with client side hashing is that it effectively makes the result of the hash the password rather than the password. There is nothing to stop an attacker from bypassing the official client and simply sending the finished hash to the server directly. It provides no additional (or loss) of security during the authentication, but under the situation that hashing is designed to protect against, it offers nothing since the hash stored in the DB is actually the shared secret transmitted to the server.
That said, there are two notable thing client side hashing does give you. While it doesn't help protect your system at all, it may help protect your user. If you are insecurely transmitting the password or the transmission gets compromised without the client code getting compromised, you will still protect the user's password (which they may reuse on other sites) from being leaked.
The other is that you can provide additional iterations of a hash to make an offline attack against the DB more difficult without having to use server cycles (while also extending the length of the "intermediate password that the client submits"), but you still need sufficient server cycles to protect the lengthened password against a rogue client. Again, the primary protection this offers is preventing the original password from being discovered but does nothing for helping protect the authentication mechanism of your site.
Put another way, while it does provide some minor protections, from the point of view of the server, the client side hash should be treated as if it was the user's direct password. It provides no more or no less security on the server than if the user had directly given their password and should be protected as such.
If you want to be able to provide that extra level of security, I would recommend two hashes. Hash once client side to build a new, unique password, then hash that password on the server to make a value you store in the DB. This way you get the best of both worlds.
For the most part, SSL is trusted sufficiently to protect the exchange that the initial hash prior to transmission is seen as unnecessary though and a compromised server could always alter the code sent to the client such that the initial hash isn't performed. It simply isn't an effective alternative to SSL and doesn't offer enough additional advantage to be worth the costs and complexity.
If you have quite a few advantages, then you should list them in your question so that people will find out whether they are truly useful (and you may become famous if so ;)
People don't favor client-side hashing because they have better ways of protecting users private information. Let's think about the places with potential information leaks and there are three of them:
- The client.
- Between the client and the server.
- The server.
Then let's see why or why not client-side hashing will help in these places.
The client.
If there are malwares on your own computer, for example, if your browser is compromised or your computer is implanted with key-logging software, client-side hashing doesn't prevent a hacker from getting your password. The reason is obvious.
Between the client and the server.
There is the communication channel between client and server. If there is an eavesdropper listening for the communication, then client-side hashing can make the leak of password more difficult because the eavesdropper has to recover the original password from its hash. It's indeed useful here.
However, this vulnerability is based on the presupposition of an insecure communication channel. In reality, there are protocols whose existence tries to solve this problem exactly. Their major task is to establish a secure channel over an insecure one. The most famous and widely deployed example is SSL/TLS, and it provides more functionality and better security than client-side hashing.
The conclusion is that client-side hashing is helpful in the channel, but here are better tools.
The server.
Users information may be leaked on the server if the server is compromised by a hacker. The hacker can fetch user passwords from database if they are stored in plaintext. That's why today most servers don't do that. Instead, they store hashes of passwords so that hackers can't easily restore the original passwords from their information at hand (i.e. hashes).
You may be tempted to believe things still work well if the server simply stores hashes computed on the client side. But this is severely wrong. In that situation the hashes themselves become password equivalents. The hacker can pass authentication by simply handing over the hash without reversing it. The goal of a hacker is not reversing a hash, but breaking into your account. The importance lies in the server's verification process on client data, not on the fact that the data is a hash value. Therefore the benefit of client-side hashing is trivial here and the server must rehash anyway.
To summarize, client-side hashing is helpful in protecting user information, but the protection largely applies to the communication channel. Since we have better approaches there (SSL/TLS), the application of client-side hashing is greatly surpressed. It's simply not the best tool for the task at hand.