2

Typically a server ends up observing the plaintext password sent by a user at some points (correct me if it is not). Assuming that there is a secure channel established and the data are confidential, while salting and heavy hashing will be performed on the server side. So,

  1. It is a big problem that the server can see the password during authentication?

  2. To what extent could hashing on client side solve this problem, where only h(p) is sent instead of p?

  • If you hash the password client-side, then the hash is the password. Send it to the server and gain access — that’s what a password does. So any compromise of the hash becomes as bad as a compromise of the password. – Mike Scott Nov 3 '18 at 8:09
  • Potential duplicate? security.stackexchange.com/questions/8596/… – schroeder Nov 3 '18 at 8:20
  • 1
    Sorry for making my question obscure. The main focus of this question is that is it appropriate to let the server reads the actual plaintext password during authentication – Kaden Kan Nov 3 '18 at 8:36
  • @MikeScott Isn't that safeguarding the visibility of the plaintext password? – Kaden Kan Nov 3 '18 at 8:45
  • 1
    @KadenKan But if the hash is what the server uses to authenticate you then it’s the hash that you need to secure. And the hash will be visible to the server. – Mike Scott Nov 3 '18 at 10:25
3

As others have pointed out, client-side hashing doesn't really solve the problem, since the server still sees something that can be reused to authenticate (via a pass-the-hash attack). It's still better than passing the plaintext password, since people reuse passwords (but not salted hashes) between sites/services, and even when they don't they often use similar passwords (/password-choosing systems/etc).

BTW, this isn't just a server security problem. TLS interception (by client-side network security devices) is getting annoyingly common, and any device that does interception also has access to the passwords or hashes.

Fortunately, there's a solution: asymmetric password-authenticated key exchange (PAKE) allows authentication without exposing or storing anything password-equivalent on the server (or to an interception device). Secure Remote Password (SRP) is the best-known and most popular PAKE protocol. There's also a new PAKE protocol proposal, called OPAQUE that looks even better (though I want to see the crypto community beat on it for a while before I'd use it). Matthew Green has a good summary of this here.

Unfortunately PAKEs aren't very widely known or used. IMO, this really should be the standard way of doing network authentication.

Oh, and there is one big limitation: if this is implemented in server-supplied JavaScript, someone with sufficient access to it (or a TLS-intercepting box) can modify the JavaScript that's sent to the client to leak the password. There are ways to improve this somewhat (e.g. with subresource integrity), but even without those PAKEs at least narrow the vulnerability.

  • Especially important for encrypted cloud storage/password managers, allowing true zero-knowledge systems to be built. – Ben Nov 4 '18 at 18:28
2

Exposing the plain password is always a problem, sometimes more and sometimes less. If the attacker manages to compromise the server he could grab the plain passwords when the server checks if these are correct. Similar extensive debug logs at the server might inadvertently log the entered passwords too so that an attacker might grab these from the servers disk or from external backups.

Thus, it might be a good idea to protect the password against the server too. Only this is not easy since the server ultimately needs the password or something equivalent to authenticate the user.

One way would not be to send the original password from the client to the server but use some algorithm to derive the server-side password from the user-entered password - a key derivation function (KDF). This is like you suggest with h(p). Of course, this derived key should have the same server side protection as a plain text password would have since it is essentially a plain text password, only not as easy to guess. This means the derived key should be stored properly password-hashed on the server side. If this derived key depends on the servers domain or anything else site-specific it might at least protect a bit against password reuse since the same password will result in a different derived key depending on the site. Of course if deriving the key from the password is done in server-provided code then an attacker might change this code in order to grab the original password too - but this requires more effort and thus this method decreases the total risk.

Even better would be if the password is only used locally at the client to protect a client certificate inside the browser and then use mutual authentication in https. In this case it would not be sufficient for the attacker to attack the server but each client would need to be attacked. On the other hand client side certificates are more a hassle to employ than a simple password and thus are rarely used. In other words: less risk at the cost of less usability.

Apart from that there are also challenge-response methods like Digest-MD5. Only these digest functions have the problem that either the users password or something equivalent need to be stored at the server side without the protection the usual one-way password hashing offers, thus increasing the attack surface there.

1

Other answers and comments have already revealed that the security of the authentication mechanism does not really change by first applying a hash function (it may even get reduced if long input passwords are common).

I would like to point out that hiding the original password may indeed guard the users and their password creation strategies.

Users having the same password for many sites may benefit from hashing if a site specific key is included. Password generation schemes applied by a user (like "mypw4site1.com", "mypw4site2.com", ...) are hidden from any man in the middle too.

Of course any personal information which might be contained in the password (like names or birth dates of relatives) gets hidden too.

0

By sending a hash of the password, instead of the password itself, all you are protecting is the cleartext of the password. This has some merit, but it does nothing to protect against replay attacks - this is known as pass-the-hash.

By combining the users password with a single-use salt (challenge) supplied by the server, you can protect against such an attack - but in order to validate the token presented (h(p+c)), the service needs to recreate the same hashed value - i.e. it needs to store the plain text of the password. That's not good.

Conventionally, an authentication service will store a hash of the password with a randomly generated salt (h(s+p)), along with the cleartext of the salt. The clear text of the salt is not considered to be particularly secret - the effectiveness of the mechanism is not greatly weakened by revealing this. So, in principal, the server could send both a challenge and the client would send back:

 h(h(s+p)+c)

Sadly, this does not solve the pass-the-hash problem as a knowledge of the data (h(s+p)) stored on the server is sufficient to be able to authenticate.

The only practical way to avoid the problem is to use an authentication service trusted by both the client and the application service - e.g. using kerberos or openid - that just moves the problem to the authentication service, but this separates and decouples the responsibilities.

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.