Several questions on this site address client-side password hashing, and none of them admit to any security benefit beyond protecting other sites the user might use the same password for.

However, there seems to be one circumstance that has not been addressed, where I feel client-side hashing may improve security after-the-fact against some leaks - notably Heartbleed. The best response to such bugs is indeed changing passwords, yet users are hesitant to do that and websites almost never wish to require it.

Imagine hashing went like this.

  • The client has a plain-text password.
  • This is hashed to H0 and then to H1.
  • This is sent to the server, which hashes this to H2, which is stored in the database.

Then let's say Heartbleed happens, or some hacker injects code into the hasher to email H1 to himself, or any other security bug happens that completely compromises the server (but not the client) for some period of time. The exploit gets discovered and fixed, yet all H1 hashes are deemed compromised.

Let's say, like experience shows, resetting everybody's password is not an acceptable response for business reasons.

With this method, one can work around this.

  • Patch the client to now send (and the server to now require) the hash H0.
  • H0 becomes the new password.
  • H0 is unknown to the hackers, yet still verifiable by the server.
  • If needed, an alternate hash, H1', can be produced from H0 to replace H1.

Obviously this still reveals enough to allow local brute-force attacks by the attacker, so it is not a full cure. However, it seems much preferable to leaking the plain-text password, especially if the user is not willing to update it or will at best replace it with "${old_password}2".

I know little about security, so I've likely missed some important caveat, though. Thoughts?

  • 1
    How are H1 and H1' created? – Neil Smithline Jul 26 '15 at 21:17
  • They are hashes of H0. The correct hash function to use is left to someone who knows more cryptography than me. – Veedrac Jul 26 '15 at 21:21
  • How would you update the password in your database if there was an exposure as you only have the hash, not the original password? – Neil Smithline Jul 26 '15 at 21:46
  • 1
    How do you compute the new H2 on the server ? You can't obtain H0 from H2. – r00t Jul 26 '15 at 21:46
  • The idea is that H1 becomes your new H2, and H0 your new H1. (The "If needed, an alternate hash, H1', can be produced from H0 to replace H1." part refers to the server asking once for H0 to validate against H2 and then replacing H2 with hash(hash'(H0)). From then on the client will be the only one producing H1'. You can just ignore this part if you want, since it's not important.) – Veedrac Jul 26 '15 at 21:58

There are no theoretical benefits from hashing client-side and server-side to hashing twice server-side ; unless the connection between the client and server cannot be trusted.

However in practice, I have seen multiple instances where plain-text passwords ended-up in logs (mostly in error logs). In this particular scenario it has a clear advantage.

I believe you hashing from H0 to H1 is feasible with a salt that is unique per password.

Once H1 is compromised, because the server knows this particular Salt, the client could authenticate by sending H0, and then the server can check that H0 + Salt => H1. Then the server could change the Salt to Salt' and register the H0 + Salt' => H1' as the new password.

I think this is possible, but I'd advise against it : Complexity is the enemy of security.

  • Does "Complexity is the enemy of security." hold if the threat is real? I am, after all, positing that this would have helped against Heartbleed and you do yourself mention passwords ending up in logs. (Of course, I'd rather the experts write the code.) – Veedrac Jul 26 '15 at 22:19
  • The threat of introducing more vulnerabilities is also real. But this is subjective. I just don't feel that it is really worth. You are better properly securing the data in the first place. – Nate Jul 26 '15 at 23:05

Hashing of the password prior to transmission happens for some authentication protocols, most notably the WAP/WPA2 PSK four way handshake. In this scenario, the WPA protocol needs to prevent against a masquerade attack, such that a rogue AP cannot obtain the plaintext password when prompting clients for authentication.

In this protocol, an attacker who has obtained H1 = hash(H0) may use this value to authenticate without needing to know the cleartext password. Which is a violation of CWE-294: Authorization bypass by capture replay. Additionally, there is a concern with calculating a password hash using hash(hash'(H0)), as a password-salt is not used (CWE-759), and therefore a precomputation attack poses the "shortest path to compromise".

If implemented properly, an authentication system built on zero knowledge password proof significantly lower the impact posed by memory disclosure attacks such as heartbleed, log disclosure vulnerabilities, and some aspects of MITM. However, dictionary based password cracking is more or less unaffected.

  • Sorry, there was an implied salt in the process. I didn't mention it for brevity. If it wasn't clear H1 = hash(H0) and H1' = hash'(H0). I thought HTTPS was meant to prevent against snooping and replay. – Veedrac Jul 26 '15 at 23:07
  • I'm interested in the zero-knowledge password proof you mention, but it's the first I've heard of it so I can't immediately comment. Nonetheless, +1 for that. (AFAIK, Google and other big sites don't do this, though. Why is that?) – Veedrac Jul 26 '15 at 23:08
  • 1
    @Veedrac Google may not use this method for HTTP authentication because the security gain is only in edge cases, and it is fairly complex to do correctly. Zero password proofs are useful, but two-factor authentication protects against a much broader category of attacks. Google Authenticator is a cool service. – rook Jul 27 '15 at 0:33

I think the flaw in your plan is your statement

H0 is unknown to the hackers, yet still verifiable by the server.

This is not the case. Remember that hashes are one way. All the server has received from you is H1, which they have converted into H2 (and which is now compromised). The server does not know what the input was which generated H1 (i.e H0). Furthermore, it is assumed the server has only kept H2 and does not retain H1. If they had retained H1, then yes, they could has H0 and compare to H1, but they have kept H2.

If you think about it, while H1 is what you originally sent to the server, from the server perspective, it is just a password - a potentially long password, but just a password none the less. The server then needs to hash that password to store it (creating H2). We would also hope that the server has no record of H1. When you authenticate, you send H1 which the server hashes to get H2. For your scheme to work, the server would also need to keep H1, which would be like keeping a plain text password. Once a hacker got hold of the database of H1 hashes, they can access the server as the user associated with that hash without having to do anything else.

The other slightly glossed over part of your suggestiong which probably needs more thought is

Patch the client to now send (and the server to now require) the hash H0.

That is a potential problem or at the very least, likely to be as much work as just changing your password. If you were to allow this sort of pathing automatically and thereby reduce/avoid the need for the user to take action, your opening up another potential security problem - how/who would initiate that patching and how would you prevent unauthorised patching. If you want the user to do the patching, it will probably take more effort to get right than just getting them to change their password.

EDIT: As pointed out in the comment, you could verify the H0 hash by hashing it twice H0 -> H1 -> H2 and comparing with the H2 the server has. So perhaps that part of the equation might work.

However, the patching or coordination of the move from using H1 to using H0 is still problematic IMO. 'Normal' update/patch mechanisms will not work as such mechanisms rely on a single trust 'source of truth'. For example, if your on windows you trust the windows update service and if your on OSX you trust the OSX update service. But with respect to web sites, we are dealing with decentralised infrastructure.

Consider an environment where this scheme has been adopted by all or some subset of all the web servers out there. If a web server is compromised, then somehow it is necessary for that server to inform the client that they now need to send H0 rather than H1. At this point, things begin to get very complex and complexity is the natural enemy of security.

You can't make the change globally i.e now require all sites which use this scheme to use H0 instead of H1 because this would cause a coordination issue - you would somehow need to tell all servers which use the scheme to switch to the H0 -> H1 -> h2 method. Now you have to update servers and clients and coordinate that change or some sites would stop working.

Therefore, you would need to do this on a per site basis. This means you would need to have some mechanism built into your scheme which allows the server to tell the client which hash it wants for authentication - H0 or H1. Now you have another problem. How do you protect against a rogue server asking for H0?

Given that one of the biggest problems with any password scheme is that people tend to use the same password on multiple sites. We know this is bad practice, but people do it anyway. If you were to visit a bad server, it could ask for H0. Now that server has H0 and can hash it to get H1 and use that hash to access other servers you might use which are still relying on the original H1 as password. This could even be part of another attack vector on compromised hosts - once you have compromised a host, you could start asking for H0 hashes.

the real problem here is that we are adding additional complexity, which will add unforeseen 'holes' which only adds minimal possible additional security and fails to fix the fundamental (and probably unfixable) approach of using passwords to secure access - bottom line is passwords as an access control on their own is just fundamentally broken. What is really needed is a convenient way to add additional factors to the authentication process and move away from approaches which rely on a simple secret word

  • You just verify H0 by hashing it twice (with the two salts). Patching the client goes through the usual update mechanisms, whether that's just updating the webpage (in which case the user wouldn't even be aware) or using a secure update channel (which, eg. Chrome has). These must be like solved problems, else Chrome and Windows wouldn't have automatic updates. – Veedrac Dec 6 '15 at 9:01
  • "we are dealing with decentralised infrastructure." → If updating all servers at the same time is a problem, update incrementally and after the switch is finished disable the old version. // "people tend to use the same password on multiple sites." → If the user gives away their key, nothing I do is going to stop that. // "once you have compromised a host, you could start asking for H0 hashes." → If your host is compromised to that degree, nothing can help you. I don't think that's my problem to solve. – Veedrac Jan 7 '16 at 22:10
  • "the real problem here is that we are adding additional complexity, which will add unforeseen 'holes'" → My question was precisely to ask about these unforseen "holes". // "which only adds minimal possible additional security" → It would have significantly helped after-the-fact responses to Heartbleed and equivalent. Given Heartbleed was a major thing, I don't see how you can call this "minimal possible additional security". – Veedrac Jan 7 '16 at 22:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.