4

Say I have a client and a server. I want the user with the client to login to the server with a username and password combination.

To login, they have to enter the right password which (when hashed) matches the details stored on my server.

Where do I perform the hashing function on the password entered by the user? Should the client's computer perform the hashing function and send the hashed result to my server (hoping that nobody figures out a working hash to send)? Or, should the server perform the hash on the password (hoping the connection between the two is secure)?

I'm keeping this as abstract as possible in hopes of applying it to multiple situations.

2

4 Answers 4

5

Think about the purpose of hashing.

If someone breaks into your database they will not find passwords but only hashes which need to be brute forced into passwords in order to be useful.

By allowing the client to send a hash instead of the password you effectively make the hash the new password and all benefits are lost. i.e. if someone gets into the database they can instantly log into all accounts with the data they find there.

Therefor the client should always send the password and the server should do the hashing.

4
  • This makes sense. The point of hashing is to prevent people from stealing passwords in the DB so they can't login with them, but if they can just steal and send the hashed password then hashing was just a waste of computational time.
    – Erikster
    Commented Mar 25, 2014 at 15:25
  • I think you're skipping a step though. Allowing the client to hash the password doesn't preclude the server from doing it too. Commented Mar 25, 2014 at 19:45
  • The client hashes the password and does what with it? The server still needs to know the password one way or another to assert that the hash is correct. Commented Mar 26, 2014 at 9:08
  • Yes, but the server can hash whatever value it gets (the pre-hashed password) before storing it. Just because the client hashed the password doesn't mean the server can't too. Commented Mar 26, 2014 at 15:16
10

Ideally, we should do most (but not all !) of the hashing on the client side.

The overall need for password hashing, with all the involved iterations and salts (see this answer), is to make sure that the value which is stored (the "password verification token") cannot easily be used for an offline dictionary attack (the attacker tries potential password, until one which matches the stored value is found). For that specific functionality to be fulfilled, it suffices that the slow-and-salted password hashing occurs "somewhere", and the client machine is a reasonable place for that.

However, protection against offline dictionary attacks is only one part of the security goal. In particular, we do not want an attacker to be able to obtain "password-equivalent" values. If you do the complete hashing client-side, and store the value "as is" on the server, then a glimpse on the server's database (as happens all too often with SQL injections and lost backup tapes) will reveal the hash values and allow the attacker to log in as any user immediately. Thus, you still want to do some hashing server side.

What works, for instance, is to have the slow-and-salted hash on the client, resulting in a value V, and the server stores SHA-256(V). Since the slow-and-salted hash has been done, the protection against dictionary attacks is there; and since the server does not store V but still requires the client to send V to be granted access, read-only breaches are not trivially escalated into full read-write compromise.

Client-side hashing has the very interesting feature of using client-side resources, not server-side, thus allowing a given server to process many concurrent clients without running out of CPU, while still having an overall slow-and-salted password hashing. However, this is not often done in practice because of some drawbacks:

  • The client cannot hash without knowing the salt, which is stored on the server. The protocol thus implies an extra roundtrip: the client must send the username, the server responds with the salt, and then (only then) can the client do the slow-and-salted hash.

  • Clients are heterogeneous: some can be quite feeble, which implies a hard limit on the number of iterations that can be applied (because a slow smartphone as client does not mean that the human user is more patient). This is especially true for Web-based clients, because Javascript computations are awfully slow (when compared to native code or even Java or Silverlight applets).

  • Client-side hashing means client-side code, which may not be easily upgraded or modified. With server-side hashing, the hash function choice is entirely up to the server and can be switched without having to alter installed clients in any way.

  • Some servers like to have access to cleartext passwords occasionally, not for storage, but for other features such as automatically detecting very poor user passwords, or sending a copy of the passwords to the relevant Law enforcement authorities (where applicable -- I am not saying that this is good or bad, but when it applies, it is not subject to a choice by whoever designs the login system; if you are in a country where you must allow governmental agencies to peek at passwords, then, well, you must, so this becomes an element of the context to be dealt with).

2
  • a much better answer than the accepted answer.
    – NH.
    Commented Aug 5, 2017 at 16:36
  • Surely if the database is compromised and the SHA256(V) is compromised, then accounts are effectively protected only by the SHA256, which can be brute-forced much easier than is acceptable (and the length of the input may be pre-known, as V is calculated on the client side, so the algorithm is exposed even to SQL injections)
    – Hack5
    Commented Sep 15, 2020 at 18:33
4

Passwords should be hashed at least once on the server, to prevent pass-the-hash style attacks where a malicious attacker can simply inject the hash he sniffed from the network to authenticate. This doesn't however mean that you shouldn't hash the password locally as well. A fairly paranoid strategy is to have the user submit an iterated hash of a password, using a large number of iterations, say 10,000, which you then store.

When the user wants to authenticate they enter the same password, but only hashed 9999 times. The server then locally hashes the 9999-times hashed password once, and if it matches the stored 10,000-times hashed password the server replaces the stored hash with the 9999-times iterated hash. On each subsequent attempt the user iterates the hash one fewer times, and if authenticated successfully the server replaces the old hash with the new hash.

The user is forced to reset his password when the number of iterations becomes low. Various tactics can be used to incorporate salts at various points to add additional security. The server should also hold the number of iterations it expects the client to have submitted so that the client (or multiple clients) can be kept in sync.

In summary, always hash the password on the server, but that doesn't prevent you from hashing locally also, which can also prevent the server from ever knowing the user's password, even briefly.

9
  • Do you have a source explaining how this iterative hashing strategy works? Or the name of it so I can look it up? It's not really adding up in my head. Commented Mar 25, 2014 at 15:35
  • 1
    In what situation does this improve security? The cases I can think of are: (1) attacker has the plaintext password -> you lose (2) attacker has a hashed password and tries to log in with it -> server rejects it because it wants the plaintext (3) attacker has a hashed password and tries to track it -> re-hashing it on the server side doesn't make this any harder since the attacker only needs one valid password hash. Commented Mar 25, 2014 at 19:44
  • The goal with this strategy is to assure the client that the server, whether maliciously or accidentally, cannot leak his passwords, even if the server is always malicious. The client can guarantee the server cannot leak his password, because the server never sees it, not even at account creation. The reducing hash means that an attacker cannot just pass the hash, because each hash is only good once. The salting scheme is necessary to prevent the attacker from forging a login page with a low hash number to obtain a large hash chain. I saw this in a paper I read years ago, I'll look for it.
    – jhoyla
    Commented Mar 25, 2014 at 21:22
  • "have the user submit an iterated hash of a password, using a large number of iterations, say 10,000, which you then store.", "When the user wants to authenticate they enter the same password, but only hashed 9999 times." "The server then locally hashes the password once," In this last step how does the server know what the password and how can it get the 9999th hash iteration if all you have provided is the 10000th hash iteration? I don't like downvoting but this is either very poorly explained or completely made up. Commented Mar 26, 2014 at 9:12
  • 1
    On account creation the server is given the 10000 times hashed password. On the subsequent login the server is given the 9,999 times hashed password, which it then hashes once to check it is correct. If it matches the 10,000 times hashed password then the server authenticates the client. The server then replaces it's copy of the 10,000 times hashed password with the 9,999 times password which it was sent by the user. It never reverses the hash, it simply checks if the user supplied hash matches. insert unnecessary disparaging comment here
    – jhoyla
    Commented Mar 26, 2014 at 14:06
0

Should the client's computer perform the hashing function and send the hashed result to my server (hoping that nobody figures out a working hash to send)?

If you use firefox, I highly suggest you download a simple little tool called "TamperData." Turn it on and see what kinds of havoc you can play if you sit in between the client and the server.

So the answer to this question is: NO. The best way to handle this is to store a salted hash on your database and your server application treats all incoming data as malicious. In your case, how would you implement the client hash? In Javascript? In order to verify the hash, server and client code must be in lock-step, and since the attacker has full access to your Javascript hashing algorithm... you've actually made an awful lot of implementation information public, such as which hash you're using, you'd have to give away your salt too--just far too much to trust to chance. Better that your pages be simple and dumb, and leave the validation for the server application. Usability might require some client-side validation, just be careful here because again, you're giving away implementation details to your possible attackers.

In short:

  1. Assume all source (client/server/database) is public knowledge and freely available. A sub-point here is to also remember that inlcuding Javascript libraries in your pages opens you up to attack. Better to have local copies in your organization that have been professionally vetted. Watch out for webservices too! Just because a fortune-500 exposes a webservice doesn't mean that an attacker can't leverage their input/output against you!

  2. Find your boundaries--in MVC applications like web applications this is pretty easy. Anything coming from the user is treated as hostile until validated.

8
  • Making the hash function and salt public isn't a big deal though. If you know what you're doing, the hash function will be obvious (PBKDF2, bcrypt or scrypt) and the salt is just a random number which is useless by itself. Commented Mar 25, 2014 at 19:40
  • How would the hash be obvious to an attacker that only has access to the HTML src?
    – avgvstvs
    Commented Mar 26, 2014 at 15:12
  • It doesn't matter. The hash function can be public and it won't hurt your security at all. Commented Mar 26, 2014 at 15:18
  • My point was purely about hiding your application's implementation. We're talking about passwords. If your client code contains both information about which hash you're using, and the salt, you just radically decreased the difficulty of building your rainbow tables. Hashcat for the win.
    – avgvstvs
    Commented Mar 26, 2014 at 16:28
  • And since I'm on my soapbox, what JavaScript PRNG would you use? Further, since its JavaScript as an attacker there are means by which you can subvert a site-user's browser session and redefine any functions you want. No, the more I think about it, I will never agree with exposing hash + salt code on the client and leaving the rest up to chance. How does the server know that the salt is valid and not tampered with? How does it know the salt was actually random?
    – avgvstvs
    Commented Mar 26, 2014 at 16:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .