2

I am trying to achieve better security in my authentication system implementation with both server-side hashing and client-side hashing. (See the first reference below for more prerequisite knowledge.)

As I understand it:

  1. Client-side hashing prevents hackers from getting a user's plaintext password and using it for other sites when the server app is compromised. Compared to server-side KDF hashing, it can also help lighten the server load.
  2. Server-side hashing prevents hackers from logging in as users when the server database is compromised.
  3. KDFs such as Argon2 make it expensive for hackers to brute-force a list/dictionary of common or possible plaintext passwords against a hashed password.

I'd like the save some server computing resources. So here comes my question: is it safe to directly hash "a password already hashed with Argon2 on the client-side" on the server-side with SHA-256? Here I mean "safe" by being at least as safe as using server-side only Argon2. Besides, The second reference below also suggests hashing the authentication token (the so-called "validator" in their article) with SHA-256. Is doing this safe?

My answer: an Argon2-hashed password or an authentication token with a length of at least 16 bytes should be safe. The reasons are:

  1. There is no list/dictionary to try since the data is a byte string that can be anything.
  2. A full rainbow table of all 16-byte-long keys should contain 2 ^ 128 entries, which takes at least 2 ^ 128 * 32 B = 2 ^ 133 B ≈ 8 * 10 ^ 39 B = 8 * 10 ^ 27 TB of storage, which is way too big.
  3. Even if we take the peak Bitcoin hash rate till now 170000 Phash/s, it will still take 10 ^ 12 years to enumerate all the possibilities.

However, I am no security expert so I am not sure whether there are any other flaws. So it would be nice if someone professional could share his/her opinion on this.

PS: Here are the related articles and questions I have read and think are useful, and got me into this question.

  1. authentication - Why is client-side hashing of a password so uncommon? - Information Security Stack Exchange
  2. Implementing Secure User Authentication in PHP Applications with Long-Term Persistence (Login with "Remember Me" Cookies) - Paragon Initiative Enterprises Blog
  3. Password Storage - OWASP Cheat Sheet Series
Shreck Ye
  • 131
  • 5
  • "Safe" from what? – schroeder Sep 01 '21 at 14:09
  • 2
    Hashing passwords client-side does not make *your service* more secure. At best, it is a convenience for the user. – schroeder Sep 01 '21 at 14:10
  • @schroeder Sorry I made a mistake with the link of the first reference and fixed it. The top answer in [the first reference: authentication - Why is client-side hashing of a password so uncommon? - Information Security Stack Exchange ](https://security.stackexchange.com/questions/53594/why-is-client-side-hashing-of-a-password-so-uncommon) lists 3 points. And indeed the 3rd point suggests it is a convenience for the user as you said. This is indeed one of the things I care about. – Shreck Ye Sep 01 '21 at 14:17
  • But what do you want to be safe from? You ask if it is safe, but that's not answerable. Safe from shark attacks? Interception? Decryption? Known-plain-text attacks? Algorithm weaknesses? – schroeder Sep 01 '21 at 14:19
  • 1
    I'd say as safe as using only Argon2 on the server-side against attacks, those attacks server-side Argon2 protects against. I could find very little information on hashing both on the client-side and the server-side, but this is what I want to do. So I want to make sure it's at least as safe as using only server-side Argon2. – Shreck Ye Sep 01 '21 at 14:24
  • 1
    Can you edit your question to make that clear? – schroeder Sep 01 '21 at 14:25
  • Perhaps something like "does hashing on both server and client-side introduce weaknesses that wouldn't exist if we only hashed server-side?" – schroeder Sep 01 '21 at 14:26
  • I edited the text, but the title would be too long if I edit it to include both your suggestion and SHA-256 in it. – Shreck Ye Sep 01 '21 at 14:30
  • Till now all the answers are telling me why it's not necessary to do client-side hashing for it's "not more secure", so I edited the text again to emphasize another non-security reason for adopting client-side hashing that it can help lighten some server load. – Shreck Ye Sep 02 '21 at 07:14
  • 1
    Unfortunately, performance is not a security concern. I think you really need to change the question to what I suggested in order to avoid getting the answers you don't want. And also state what you've stated in the comments, that you want to provide this convenience to the users and that you know that it doesn't improve the security of your service. – schroeder Sep 02 '21 at 07:16
  • @schroeder OK it's done. – Shreck Ye Sep 02 '21 at 07:27
  • 1
    OP, I agree with you that this could be used to lighten server load. It also provides a (narrow) benefit to users in protecting them to some degree if they use the same password on multiple sites (as argued by the answerer in the link that I referenced in my answer). However, I think there are better ways to achieve these benefits (namely PAKE or SRP), which offer other additional benefits as well. See https://security.stackexchange.com/questions/242811/alternatives-for-sending-plaintext-password-while-login/242824#242824 for more info. – mti2935 Sep 02 '21 at 11:03
  • 1
    OP, in your implementation, where would the salt (as needed for the client-side Argon2 hashing) be stored? If on the server, then you would need to work out some protocol for the client first getting the salt for the user from the server (and at that point, this begins to look very much like PAKE/SRP). If on the client, then this presents usability issues with clients logging in from different browsers/devices, etc. – mti2935 Sep 02 '21 at 11:44
  • 1
    @mti2935 Thank you very much. I roughly learned about PAKE and SRP and this is quite helpful. In my implementation, the salt would be stored on the server and it's true that every time the client logs in it needs to get it from the server, so it makes the login process more complex as mentioned in the link you shared. I think you can include the content in these 2 comments in your answer below. This is indeed helpful. – Shreck Ye Sep 03 '21 at 09:41
  • Glad it helped. As requested, I summarized the points that we discussed, and appended them to my answer below. – mti2935 Sep 03 '21 at 12:30

3 Answers3

4

I beg to differ regarding:

Client-side hashing prevents hackers from getting a user's plaintext password and using it for other sites when the server app is compromised.

The client-side scripting that does the Argon2 hashing would have to be served by the server. If the server app is compromised, then the attacker can alter this client-side scripting, so that it captures the user's password before it is hashed, and sends it to the attacker's server.


Questions like this seem to come up from time to time on this board. See the comments (and banter) following the answer at Is it safe to send clear usernames/passwords on a https connection to authenticate users? for one recent example. It seems that there are few (if any) security benefits of client + server hashing as compared with the standard method of sending the plaintext password over https, and salted hashing on the server side; and the use case for client + server hashing is very narrow at best.


Edit 9/3/2021

As requested by OP, I am including two points from our discussion in the comment's following his question (above).

  1. I agree that this could be used to lighten server load. It also provides a (narrow) benefit to users in protecting them to some degree if they use the same password on multiple sites (as argued by the answerer in the link that I referenced above). However, I think there are better ways to achieve these benefits (namely PAKE or SRP), which offer other additional benefits as well. See Alternatives for sending plaintext password while login and Hashing Passphrase in Client-Side JavaScript Rather than Server-Side -- Is it Viable? for more info.

  2. The question of where the salt (as needed for the client-side Argon2 hashing) would be stored must be addressed. If on the server, then some protocol would need to be worked out for the client first getting the salt for the user from the server (and at that point, this begins to look very much like PAKE/SRP), then proceeding with the client-side hashing, and finally authenticating with the server. If on the client, then this presents usability issues with clients logging in from different browsers/devices, etc.

Last but not least - Any of the implementations discussed in the answers and comments following this question would involve client-side (on 'in-browser') crypto - meaning that the server would need to serve-up client-side (e.g. javascript) crypto code. If we don't trust the server with our plaintext password, then how can we trust the server to serve secure crypto code? A rogue server admin (or an attacker that has gained access to the server) could modify the crypto code that the server serves, and capture the user's plaintext password, as I alluded to at the beginning of this answer. This is the infamous browser crypto chicken-and-egg problem. I realize that this is tangential to the question - but if/when we have a solution to this problem that is well-adopted (or if/when browsers implement a protocol like PAKE or SRP natively), then there might actually be tangible security benefits to a solution like one the above discussed here (over the standard method of sending the plaintext password over https), in addition to the other benefits mentioned.

mti2935
  • 21,098
  • 2
  • 47
  • 66
  • The salts aren't supposed to be secret, are they? Couldn't the client just ask for the salt? To avoid user enumeration the alt can be a function of the username and a secret. I'm also trying to understand if client-side hashing brings any benefit in practice. It seems to me it prevents credential stuffing in the case of an attacker being able to sniff TLS. But as I [summed up in my question](https://security.stackexchange.com/questions/263882/on-the-gains-and-losses-of-an-additional-client-side-stretching-of-the-user-pass) this scenario is unlikely and implies a catastrophic failure anyway. – Margaret Bloom Aug 05 '22 at 10:38
  • @MargaretBloom, please see my response to your comment in the question that you posted. – mti2935 Aug 05 '22 at 10:52
2

So here comes my question: is it safe to directly hash "a password already hashed with Argon2 on the client-side" on the server-side with SHA-256? Here I mean "safe" by it's at least as safe as using server-side only Argon2.

Leaving aside any possible concerns with the cryptography, there are a couple of important other questions that you need to consider:

  • Is the client-side library you're using for Argon2id as robust as the server-side implementation?
  • Can you guarantee the integrity of this library when it's used (i.e, that an attacker can't tamper with through a MitM attack, XSS vuln, etc)?
  • Can you create an equally strong hash on the client-side (based on the parameters you configure the algorithm with) as you can server-side without an unacceptable performance impact on the client? How about for mobile devices?
Gh0stFish
  • 6,800
  • 1
  • 23
  • 23
  • Here are my answers: * I am going to use the "libsodium.js" lib which is maintained by "libsodium"'s authors so I think it should be robust enough. * If an attacker can change the JavaScript code then he/she can send the plaintext password directly to his/her server, so in this case, server-side Argon2 doesn't help either. * Mobile devices are getting more and more powerful these days with octa-core CPUs so I think they can handle. On the contrary, if I use server-side only Argon2 and when there are too many login requests, it can affect the throughput of the server. – Shreck Ye Sep 02 '21 at 07:42
  • Have you actually tested how well the libsodium.js library performs on mobile devices (with your defined parameters) on a midrange phone that's a few years old? They're certainly more powerful than they used to be, but algorithms like Argon2id are intentionally designed to be slow (and should be memory-heavy, although you can tune that). – Gh0stFish Sep 02 '21 at 08:36
  • Yeah, the parameters can be tuned. there is an "INTERACTIVE" version that's designed for such online operations. – Shreck Ye Sep 02 '21 at 08:48
-2

Hashing a password on client side is 100% completely worthless.

  • If server app is compromised they can simply comment out / rewrite the javascript code to hash it client side.
  • clientside javascript should not be trusted! Ever! For any reason!
  • If you hash a 30+ character password to 16 bytes, you are actively decreasing the security of the user.
  • Hashing a password clientside effectively makes the clientside hash the real password. If its stolen, they dont need the pre-hashed version for anything.

The correct way of doing this is:

CaffeineAddiction
  • 7,567
  • 2
  • 21
  • 41
  • Not worthless. It's a convenience for the user in case of certain client-side threats. It has little to no impact on the security of the service, however. – schroeder Sep 02 '21 at 07:19
  • @schroeder How is it not worthless? What am I missing? It does not protect anything if the client side computer gets attacked. It does not protect anything if the clientside javascript gets attacked. It does not protect anything if the serverside gets attacked. It does not protect anything if their is a man in the middle attack. – CaffeineAddiction Sep 02 '21 at 14:23
  • @CaffeineAddiction I agree with you that we are not quite there yet with client-side (or 'in-browser') crypto. But, we are inching our way there - we now have CSPRNG in javascript, subresource integrity, native crypto functions in the web crypto API, etc. ProtonMail is showing that it can be done. If the user's device is compromised, then it's game over no matter what - even if it's done the 'correct way' as per your answer. But, I agree with you about a server attack. That's why I think it's time we had a way to verify the integrity of client-side code, as I mention in my answer. – mti2935 Sep 03 '21 at 13:30