167

I am building a web application which requires users to login. All communication goes through https. I am using bcrypt to hash passwords.

I am facing a dilemma - I used to think it is safer to make a password hash client-side (using JavaScript) and then just compare it with the hash in DB server-side. But I am not sure this is any better than sending plain-text password over https and then hashing it server-side.

My reasoning is that if attacker can intercept the https traffic (= read plaintext password) he can for example also change the JavaScript so it sends the plaintext password alongside the hashed one - where he can intercept it.

The reason against hashing client-side is just ease of use. If I hash client-side I need to use two separate libraries for hashing. This is not an unsurmountable problem, but it is a nuisance.

Is there a safety gain in using client-side hashing? Why?

Should I also be using challenge-response then?

UPDATE: what interests me the most is this - do these techniques (client-side hashing, request-response) add any significant security gain in case where https is used? If so, why?

8
  • 1
    stackoverflow.com/questions/3715920/…
    – amal
    Nov 2, 2011 at 10:17
  • Thanks for the link, but while the situation is similar, there is a subtle difference - I am using https. Also, I find explanation of the answers lacking... If page can be read, it can also be modified, which means the user will enter his password in a form which was supplied by attacker. I will update the question to better emphasize this.
    – johndodo
    Nov 2, 2011 at 10:34
  • 1
    Also see security.stackexchange.com/q/23006/2379
    – Pacerier
    Dec 2, 2014 at 0:26
  • 3
    Personally I think all clients should salt and hash their passwords before sending them. I don't see any reason why I would give my plaintext password to a server, when a hashed version would work just as well. I am disappointed that this is not standard practice. (And yes of course, passwords should be salted and hashed on the server too.) Jan 18, 2017 at 7:11
  • 1
    Following my rant, here is someone asking something similar as a question: How to authenticate in a website with public/private keys? Jan 19, 2017 at 10:31

13 Answers 13

172

If you hash on the client side, the hashed password becomes the actual password (with the hashing algorithm being nothing more than a means to convert a user-held mnemonic to the actual password).

This means that you will be storing the full "plain-text" password (the hash) in the database, and you will have lost all benefit of hashing in the first place.

If you decide to go this route, you might as well forgo any hashing and simply transmit and store the user's raw password (which, incidentally, I wouldn't particularly recommend).

15
  • 17
    Can you please elaborate on why you think this is so? AFAIK the only advantage to using hashed passwords is protecting users' accounts on other websites in case the passwords / hashed passwords are stolen - nothing else. If this is so then there should be no difference where the hashing is done. Is there some other advantage in hashing that I have missed?
    – johndodo
    Nov 2, 2011 at 12:35
  • 32
    Storing a salted hash is actually supposed to help protect your application against an attacker gaining credentials by reading the authentication data store contents. If he can't infer a password from the store, he can't pass it to the server for authentication. Nov 2, 2011 at 13:06
  • 9
    Aaaah,that makes sense... Attacker gets hold of hashed password, but he is not able to use it on this system because the system hashes it by itself - so he would have to find the original password first. Nice one! :)
    – johndodo
    Nov 2, 2011 at 13:20
  • 9
    @johndodo "the only advantage to using hashed passwords is protecting users' accounts on other websites in case the passwords / hashed passwords are stolen" Not only one reason. But still, it is one reason.
    – curiousguy
    Nov 4, 2011 at 0:52
  • 7
    This answer isn't really right. It highlights the vulnerability of a naïve approach to client-side hashing. It is certainly true that if the server does no hashing at all and just stores the value that the client sends, this would be no better than storing plaintext passwords. But the simple solution is to hash at both the client and the server. And with this simple solution in place we gain one significant advantage: the cost of resource-intensive password hashing can be shifted from the server to the client, and likely cranked up further than the server might be able to support. Jan 20, 2017 at 21:18
45

Hashing on the client makes sense only if you do not trust the server in some way, and do not want to show it the "actual" password (the one which the human user remembers). Why would you not want to show the password to the very site on which the said password has any use ? Because you have reused the password elsewhere ! Now that's usually bad, but there is a relatively safe version which is incarnated in myriads of browser extensions or bookmarklets such as this one or that one (I don't vouch for their quality). These are tools where the human user remembers a "master password", from which a site-specific password is generated, using the site domain name as a kind of salt, so that two distinct sites get distinct passwords.

While this scenario makes sense, doing it with Javascript sent by the server itself does not. Indeed, the point of hashing the password client side is that the server is potentially hostile (e.g. subverted by an attacker), and thus Javascript code sent by that server is, at the very least, suspect. You do not want to enter your precious password in some hostile Javascript...


Another case for client-side hashing is about slow hashing. Since passwords are, by definition, weak, you want to thwart dictionary attacks. You assume that the bad guy got a copy of the server database, and will "try passwords" on his own machines (see this blog post for some discussion on this). To slow down the adversary, you employ an inherently slow hashing process (such as bcrypt), but this will make the processing slow for everybody, including the server. To help the server, you might want to offload some of the work on the client, hence do at least part of it in some Javascript code running in the client browser...

Unfortunately, Javascript is awfully slow at this kind of job (typically 20 to 100 times slower than decent C code), and the client system will not be able to contribute a substantial part to the hashing effort. The idea is sound but will have to wait for better technology (it would have worked with a Java client, though: with a decent JVM, optimized Java code is about 2 to 4 times slower than optimized C code, for a hashing job).


To sum up, there is no really good case for doing client-side password hashing, from Javascript code sent by the server itself. Just send the password "as is" to the server through an HTTPS tunnel (the login page, the form destination URL, and whatever page are protected by the password, shall all be served over SSL, otherwise you have more pressing security issues than the use of passwords).

1
  • 1
    Facebook, Instagram, GitHub, Coinbase and Twitter are some of the high profile sites that have publicly admitted (accidentally) logging plaintext passwords. Certainly as a customer I would feel more comfortable being able to confirm my passwords are being hashed by a slow hashing algorithm client-side (using Argon2 for instance) as well as being hashed server-side.
    – Jonathan
    Apr 22, 2023 at 4:25
20

Hashing server-side is important as all the other answers have indicated, but I would like to add that hashing client-side would be a nice security feature in addition to server-side hashing.

Client-side hashing has benefits in the following scenarios:

  1. Protects user's password when server is compromised. I.e. if the client isn't compromised, but the server is, if the client hashes the password, the server could still gain access to the one system, but you've protected the user's password which is important if they use that password elsewhere.
  2. Protects user's password when the user thinks they're logging into one server but they're really logging into another (user error). For example, if I have two banking accounts, and I accidentally type one of my bank's password into the wrong bank's website, if the bank hashed password client-side that bank wouldn't know the password of my other bank. I think it would be a "polite" thing to do to hash client-side so that their plain text password is never transmitted over the wire.

Mostly it shows respect for the user's password. The user is sharing a secret that may not be exclusive to your software, so if you respect that secret, you should do everything in your power to protect it.

4
  • 2
    I wouldn't consider enabling/facilitating password reuse a benefit. And the plain text password is never sent over the wire regardless due to the use of HTTPS.
    – augurar
    Feb 8, 2017 at 19:02
  • 4
    @augurar I wouldn't call it enabling or facilitating password reuse. Users are humans, and humans do unadvised things like reuse passwords. I consider it along the same lines as preventing the user from choosing a weak password. Hashing password client side compensates for the fact that many of your users will use the same password on your site as their banks. Regarding your second statement, if the server is compromised then they can see the decrypted HTTP request and the password in plaintext.
    – Samuel
    Feb 9, 2017 at 3:10
  • 3
    +1 a second, client side hashing is the only way to prove you're not farming passwords. xkcd.com/792
    – Agent_L
    Nov 24, 2017 at 15:59
  • Another consideration for you: sites like protonmail and 1password derive an E2E encryption key from your login credentials, rather than having you use separate authorization and encryption passwords. This only works if the server never sees the password, so they use Secure Remote Password protocol (which, admittedly, is quite a bit more sophisticated than hashing). Oct 23, 2021 at 6:26
13

I find all your concerns sound, but my recommendation would be to do it server-side.

There's always a fairly big chance that a user will leave their terminal unlocked, allowing manipulaton. And also; if your hashing logic is client-side you're exposing it.

Another option would be to generate the passwords server-side; then you're not sending in a clear-text password. But you'd still need to communicate the password to the user. And since most users still don't use encrypted email, I consider that less secure.

I've seen solutions to send passwords through an encrypted tunnel to a cellphone; but I doubt the security is better than the SSL. Perhaps someone could prove/disprove this?

7
  • 4
    "if your hashing logic is client-side you're exposing it." so what?
    – curiousguy
    Nov 4, 2011 at 0:53
  • Perhaps not a big deal. But I prefer exposing as little as possible. Let's say you'd get hold of a database with hashed passwords. If you know the hashing algorithm, you could generate a list of hashes from a list of common passwords, and match these.
    – rmorero
    Nov 4, 2011 at 9:37
  • 4
    @rmorero: I tend to disagree... First of all, there is not much you can do to protect against user leaving terminal unlocked, apart from sonar and similar. Also, hiding hashing algorithm is security by obscurity. You have to decide what is secret and what is not. Hiding non-secret things is usually counter-productive.
    – johndodo
    Nov 7, 2011 at 6:36
  • @johndodo True, these are valid points. And my logic above partly depends on a bad implementation. Still, I would claim that security by obscurity is only counter-productive if you're relying on it; which I do not recommend.
    – rmorero
    Nov 7, 2011 at 8:33
  • 6
    @rmorero: the danger in security by obscurity is not that much in relying on it... As I see it, the three major problems are: a) you spend your time on it instead of on real solutions, b) you could make an error and actually make security worse, and c) it makes the system less transparent and might thus hide other errors. In other words, it adds "fog" - and since a skilled hacker probably has fog lights in his arsenal, I would prefer a sunny day to face him. ;)
    – johndodo
    Nov 8, 2011 at 20:18
4

You could do both, you hash it at the client so if the attacker can get through the https security they will not be able to see the plain text password. Then hash it again at the server so if the attacker gets the passwords stored in the server he can not just send that to the server and gain access to the password.

1
  • This requires that the client-generated hash be deterministic, which means either avoiding a salt, using a static salt in client logic, or requiring that the client remember the salt used. The first case is susceptible to rainbow attack, and the second to a custom rainbow attack. The third case requires the user to remember (not great), for the client to store locally (a problem for cross-device access), or for the server to store and send over the wire, complicating the engineering. Nov 28, 2023 at 18:56
3

If you are in an HTTPS tunnel, the password or hash should be secured from Ethernet surveillance.

On the client-side maybe you could salt the hash with a session id.
This could be harder for malicious Javascript to simulate.

6
  • Its worth noting that the fixed+challenge salts with client side hashing can be used to implement a secure password mechanism over non-encrypted connections (but opbviously the session token and other subsequent exchanges are not secure)
    – symcbean
    Nov 2, 2011 at 17:21
  • @symcbean What do you mean by "secure"?
    – curiousguy
    Nov 4, 2011 at 0:54
  • I mean that the password transmission mechanism is not subject to eavesdropping.
    – symcbean
    Nov 7, 2011 at 11:58
  • 1
    @kwolbert you keep posting comments as new answers instead of comments. Would you please attach this as a comment where you mean it to be read in context and then delete the answer here? Thank you.
    – Jeff Ferland
    Aug 29, 2012 at 19:07
  • 1
    @kwolbert Welcome to IT Security! Please use the Post answer button only for actual answers. You should modify your original question to add additional information.
    – Scott Pack
    Aug 29, 2012 at 19:31
2

The accepted answer of @Nicole Calinoiu is of course correct but maybe to hard to understand at the beginning.

The point is the password should be hashed on the server in order that the malicious person cannot use the hashes that he has hacked from the database from the server to get access to your account or data.

As already said if you hash at client side and the back-end supports that, then the hash becomes your password and if the hash gets stolen via a hack, then the hacker has the password.

@Thomas Pornin answer has also come up with a very good point why you would want to hash the password on the client, but the thing that he describes in his first story can only be done if the back-end of the server does support handling hashed passwords (i.e do not hash the password if already hashed, but that somebody tries to support something like that is highly unlikely), which will most of the time not be the case I guess. The second story of him is very good.

1

Hashing the password client-side will require Javascript. Some people disable Javascript on their browser. You have to handle this scenario.

I have seen forum software that performs password hashing client-side, and sends the hash upon login if possible, otherwise the password is sent in plain text. So it works in either situation.

Sending the password in clear is not a major concern if you will be using https. Ideally your server should then refuse to serve pages in http so as to avoid man in the middle attack. The reasoning being: an attacker could forcibly 'downgrade' your connection from https to http and starting sniffing traffic (for example with a tool like SSL Strip).

3
  • 2
    "You have to handle this scenario" ... if you want to keep those users. It's 1% of people, and I think 90% of those can be convinced to turn it on if your website isn't full of crap.
    – Luc
    Jan 7, 2020 at 10:39
  • 1
    Man, it is 2020. If someone disables all Javascript on their browser, then this is their problem. Sep 22, 2020 at 14:46
  • 1
    In 2020 quite a few people use ad blockers or addons like Noscript to block Javascript selectively on some sites. You cannot assume that Javascript will always function no the client. But note that the question is 8 years old, back then not every website had SSL even for login pages (think forums). In light of this, hashing the password client-side has become pretty much useless nowadays. The fix is easy anyway, if Javascript is disabled then you don't hash the password before the form is submitted.
    – Kate
    Sep 22, 2020 at 19:45
1

Why not hash both client-side cookie and server-side stored hash differently? This way if one is compromised that the other still does not grant online access.

In app development, this was a standard logical step for offline-first operation. Password is NEVER stored in plaintext. SHA512 or some such algorithm is used client-side for password storage and checking against sign-in credentials. This hash is sent over the wire and hashed differently on sign in, server-side. If one is compromised this is detected easily and account is locked down until the password is reset by real user.

Users' password is still yet hashed a third time for private key encryption client-side. Protects against NAND memory attacks. And could be hashed yet again to protect server-side keys in a separate database.

With this model above, the only successful attack would be social engineering to obtain the real user-memorized password.

0

Here is a reason why you SHOULDN'T obfuscate the users' password on the client-side before sending it - on the assumption you're using HTTPS.

A lot of devices have password managers now, or the software on devices may have this feature. Notable examples are 1Password, Chrome Passwords, Apple Keychain etc. These services will notify you if your password has been compromised in a data dump and available on the internet/dark web somewhere, probably in places you do not know about.

If you obfuscate the password before sending it, and your storage methods aren't as strong as you think, the user won't benefit from being notified if their "Password1" (as saved in their password manager) is compromised because you're sending it as (figuratively) "UGFzc3dvcmQx".

So if an unrelated website got hacked and the user details were stolen, weak passwords could be cracked easily. All they have to do is test that password with the hacked user's email to see if it works on your website (via the browser), and viola - they're in. And they've now got both plain text and obfuscated passwords.

Sadly because you obfuscated your user's passwords client-side; if your site got hacked with your user details stolen and passwords cracked, the hackers just get a list of obfuscated details, which they could still use to log in using your API, but if they turned up in a data dump somewhere, there's nothing on that user's device to pair their leaked obfuscated password up with their account.

Remember, their password manager thinks their password is "Password1" as that's what they typed before you obfuscated it.

You might think trying to do something complex may benefit your users, but as tech and behaviours move forwards, especially with the adoption of password managers increasing, you could be doing them more harm.

TL;DR All you need is a strong password policy, a robust hashing algorithm on the server (bcrypt), and enforcing redirects from HTTP to HTTPS. Or solve this entire headache by using a third party like oAuth.

3
  • I would not go so far as to say that it causes harm, but it weakens this one helpful feature.
    – schroeder
    Jul 12, 2022 at 23:24
  • 2
    First of all, thanks for commenting! I think you misunderstood the dilemma though. The question is whether JS should encrypt the password before sending it (not necessarily in the input field if this causes problems with password managers). But still a good point - care should be taken not to confuse password managers.
    – johndodo
    Jul 14, 2022 at 17:22
  • @johndodo apologies, my naiveness just assumed we're all using SPA and JS to do a XHR requests and not actually posting forms anymore.
    – zivc
    Jul 14, 2022 at 22:25
0

Passwords should be hashed both client side with the salt using Argon2 or similar cpu + memory intensive slow hashing algorithm (to avoid brute-force attacks and rainbow-table attacks in the case of a db breach, and server-side credential harvesting) and server side (to avoid pass-the-hash attacks), with the addition of a pepper (to mitigate brute force attacks in the case of a db breach), using SHA256 or a similar fast hashing algorithm while still maintaining performance.

18
  • 1
    You don't really explain why or provide details and you have repeated other answers but with less detail. Plus, you don't get into how to manage a salt client-side. Instead of repeating other answers, just upvote them. Or provide a lot more detail to differentiate this answer from others.
    – schroeder
    Mar 31, 2023 at 7:13
  • 1
    Thomas Pornin's answer is the only one that suggests using client side "slow hashing". This term is imprecise. More precisely you want cpu + memory intensive hashing. I also don't agree with the rest of what he says in his answer as his final solution is vulnerable to server-side credential harvesting, so I made a new answer that I feel is more correct and more up-to-date (e.g. Argon2 was created in 2015 and his answer is from 2012). You need memory intensive hashing these days for ASIC resistance. Anyone can research Argon2 for more details on its mechanisms and the reasons behind them.
    – Jonathan
    Mar 31, 2023 at 18:54
  • One further detail I'll add is that normally you would use a cpu + memory intensive hashing function server-side to prevent brute force attacks but since you've done it client-side already you can use a fast hash server side. Another advantage of doing the intensive hash client-side is that your solution becomes more scalable as you're pushing intensive tasks client-side. The disadvantage is client devices might not be so powerful, but these days most mobile devices are fast enough to run browser based Argon2 through WASM or other mechanisms.
    – Jonathan
    Mar 31, 2023 at 19:08
  • 1
    @schroeder In terms of your comment on server-side credential harvesting. In 2018 Twitter revealed were password being logged and advised users change them. Client-side hashing prevents this. If the server code is compromised in any configuration (e.g. server-side or client-side hashing) credential harvesting will be possible with addition or modification of the production codebase.
    – Jonathan
    Apr 13, 2023 at 5:17
  • 1
    Client-side hashing also builds a trust relationship between the customer and the service provider as the customer can easily check if the passwords are being sent unhashed to the server or not (at least from within a web app by inspecting the network traffic). Personally I would be more inclined to use services that don't send my plain text login details that can easily by used by who knows who at the other end. You may argue I have bigger problems if someone server side is snooping but I'd rather not have that to deal with also.
    – Jonathan
    Apr 20, 2023 at 13:30
-1

If your server's going to have multiple possible administrators and you can't necessarily trust all of them to not get ram dumps, you should really hash client side to protect admins from stealing user passwords [which may be reused on other websites--despite this being bad practice, users do it and will continue to do it], and then hash that hash server side so that stealing the table doesn't automatically give attackers the so-called plaintext password for the website itself.

And as long as you're using the secure hash function, you can use the same salt for both sides.

3
  • 1
    If you don't trust your admins, you're in a much bigger world of hurt than just having to worry about them stealing an occasional user password from RAM. If you have a malicious server admin, you can't protect user passwords any longer, including by trying to hash them client side, at least for a web app.
    – Xander
    Jan 20, 2017 at 15:23
  • Well what about this cloudflare issue that just popped up? I still say hashing on both ends is the only safe way to do it. Further, if you think modifying output (the step necessary to make "trying to hash at client side" fail) is just as easy as peeking at input, you've never actually seen a physical computer.
    – codetaku
    Feb 24, 2017 at 17:16
  • 1
    You can protect from malicious, opportunistic admins by having client-side password hashing.
    – Jonathan
    Mar 31, 2023 at 5:00
-6

For all intents and purposes you will only want to hash on the client side. The idea behind a hash is to prevent anyone but the user from knowing the password. As any good site should be using TLS, the fact that the hash is being sent to the server is irrelevant (Note that even if this was a concern sending the plain text password would be just as bad).

Finally the answers listed seem to fail to realize that if the server is ever compromised every individual on the servers password will become compromised since the passwords are being sent to it in plain text.

3
  • 2
    Just because a password is sent in plain text doesn't mean it is being stored in plain text. If an attacker has compromised the server to the level of being able to see traffic coming in, they can probably modify the code sent to the client to grab the user password too.
    – Matthew
    Apr 7, 2016 at 19:22
  • 4
    If the server is ever compromised, so will be the code that the server sends to the client, to do the hashing client-side, so this is effectively a useless control against a malicious server.
    – Xander
    Apr 7, 2016 at 21:26
  • @Matthew That's visible to the user, though. Server-side capturing is not. (Also goes for Xander but I can't ping two at the same time.) If a big enough bank does client-side hashing, I wouldn't be surprised if people start monitoring the javascript files (perhaps the bank themselves from an external IP) or if add-ons pop up that check changes since one's last visit.
    – Luc
    Jan 7, 2020 at 10:49

You must log in to answer this question.

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