159

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?

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
johndodo
  • 1,825
  • 2
  • 13
  • 9
  • 1
    http://stackoverflow.com/questions/3715920/about-password-hashing-system-on-client-side –  Nov 02 '11 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. –  Nov 02 '11 at 10:34
  • 1
    Also see http://security.stackexchange.com/q/23006/2379 – Pacerier Dec 02 '14 at 00: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.) – joeytwiddle Jan 18 '17 at 07:11
  • 1
    Following my rant, here is someone asking something similar as a question: [How to authenticate in a website with public/private keys?](http://security.stackexchange.com/questions/100266/how-to-authenticate-in-a-website-with-public-private-keys) – joeytwiddle Jan 19 '17 at 10:31
  • @joeytwiddle That doesn't work unless the server provides the salt (challenge-response). Given two hashed passwords with different salt values, it is not possible to tell if the original password was the same. – augurar Feb 08 '17 at 19:05
  • Hash (at least) once on client and once on server and with different, server-supplied for each user. This way you are also protecting you users who use "baseball" for every password. – Caterpillaraoz Nov 24 '17 at 14:35
  • Nothing stops you from hashing it twice, both client-side and server-side. – SOFe Mar 24 '21 at 09:05

12 Answers12

165

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).

stefan
  • 1
  • 8
Nicole Calinoiu
  • 1,876
  • 1
  • 11
  • 4
  • 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 02 '11 at 12:35
  • 31
    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. – Nicole Calinoiu Nov 02 '11 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 02 '11 at 13:20
  • 2
    Yes, the hash of the password becomes the authentication token - but if this can be intercepted then so can the session identifier. Although the latter would only allow the session to be abused, while the former allows the attacker to open new sessions, the proposed advantage is not really that great and predicated on a MITM attack on the SSL connection. – symcbean Nov 02 '11 at 17:19
  • 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 04 '11 at 00:52
  • 6
    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. – Luis Casillas Jan 20 '17 at 21:18
  • 5
    @LuisCasilla Nope. The first sentence of the answer still applies -- hashing the password client-side does not add any additional security to the system. – augurar Feb 08 '17 at 19:10
  • Plus, it's better to control all authentication server-side, because it's obviously easier to hack a client. – William T Froggard Dec 12 '17 at 08:43
  • 1
    Your first sentence and your overall conclusions are correct but your last two sentences are completely wrong. Server-side hashing is definitely the way to go, and client side hashing does indeed make the hash the password. However, if I had to choose between a system that stores passwords in plain text or hashes client side I'd take client side hashing everytime. Client side hashing at least still protects the actual password, which is the entire point of hashing - to protect the user from their own password reuse. – Conor Mancone Mar 01 '19 at 13:13
  • 1
    I think that's why your last sentence bugs me so point. The point of hashing isn't to hash for the sake of hashing - it is to make it so that if an attacker finds your password databases they can't figure out what the original passwords were, because then they would go and break into all the other accounts the user used that password with. With client side hashing that protection is still in place, and to suggest that client side hashing is as bad as plain text passwords is just wrong. I think you've lost the forest for the trees. – Conor Mancone Mar 01 '19 at 13:15
  • @ConorMancone: I suspect that you're inferring something from my answer that was never intended. This question is about hashing on the client vs on the server, not about avoiding hashing. The answer does indicate that storage of plain text passwords is a bad idea, but it was mentioned as something of an aside since I had assumed at the time of writing the answer that the OP understood the primary reason for hashing. (Also, it is worth noting that protecting the user in password reuse scenarios is _not_ the primary reason for password hashing.) – Nicole Calinoiu Mar 01 '19 at 16:10
  • 1
    @NicoleCalinoiu your last sentence clearly states that client-side hashing is as insecure as simply using plain-text passwords. This isn't true, and is a dangerous equivocation. While worse overall than server-side hashing, client-side hashing still protects the original password from being recovered and used to attempt to break into other services, which is a critical weakness that must be protected against. Therefore, client side hashing is far better than simply transmitting/storing plain-text passwords, and I think it is much safer not to imply otherwise. – Conor Mancone Mar 01 '19 at 18:22
  • @NicoleCalinoiu RE: the primary use of hashing: I strongly disagree. Protecting the user in password reuse scenarios *is* the primary reason for password hashing. Contrary to your comment at the top of this thread, hashing only provides weak protection against attackers gaining account access if they get read-access to a database (for instance). May systems store session data in databases too, so that gives access to accounts even if passwords are hashed. Moreover, encryption could be just as effective as hashing in that scenario. We hash to protect against password reuse. – Conor Mancone Mar 01 '19 at 18:26
  • None of you all stated the other thing. hashing client side make the password LESS SECURE for strong passwords. ie, if I had a generated password using all character set (up/down/num/symbols) at long but random length, and you hashed it, by definition of hash you introduced that different passwords (collisions) can also work, and attacker has fewer 'possible passwords' to brute force. – AwokeKnowing Aug 28 '19 at 20:01
  • This answer is only correct if you **only** hash client side, and you should never do that. You must hash on the server side, and I think it's better practice if you hash on the client's side as well. – Erotemic Jun 29 '21 at 21:49
44

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).

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
19

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.

Samuel
  • 309
  • 2
  • 5
  • 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 08 '17 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 09 '17 at 03:10
  • 3
    +1 a second, client side hashing is the only way to prove you're not farming passwords. https://xkcd.com/792/ – Agent_L Nov 24 '17 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). – stewSquared Oct 23 '21 at 06: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?

rmorero
  • 231
  • 1
  • 3
  • 4
    "_if your hashing logic is client-side you're exposing it._" so what? – curiousguy Nov 04 '11 at 00: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 04 '11 at 09: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](http://stevetarzia.com/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 07 '11 at 06: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 07 '11 at 08: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 08 '11 at 20:18
  • @johndodo I partly agree with you. For a) In some cases, this is true, but if the implementation is the same for a public and a hidden solution? For b) True. But you could also make the same error in your public implementation - it would just be faster to detect? c) True, I also favour transparency; but by this same logic would you also recommend running everything in a system on standard ports? – rmorero Nov 08 '11 at 21:19
  • @rmorero "_by this same logic would you also recommend running everything in a system on standard ports?_" Not obscuring things does **not** mean that you should use standard ports. Using non-standard ports is not just obscurity. – curiousguy Aug 29 '12 at 20:46
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.

schroeder
  • 125,553
  • 55
  • 289
  • 326
  • 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 02 '11 at 17:21
  • @symcbean What do you mean by "secure"? – curiousguy Nov 04 '11 at 00:54
  • I mean that the password transmission mechanism is not subject to eavesdropping. – symcbean Nov 07 '11 at 11:58
  • bua, thanks Getting closer, But their are no sessions states, I am using flex –  Aug 29 '12 at 18:59
  • 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 '12 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 '12 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.

stefan
  • 1
  • 8
Ini
  • 29
  • 2
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).

Kate
  • 7,092
  • 21
  • 23
  • 1
    "*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 07 '20 at 10:39
  • Man, it is 2020. If someone disables all Javascript on their browser, then this is their problem. – Ekrem Dinçel Sep 22 '20 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 '20 at 19:45
1

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.

nat that
  • 11
  • 1
0

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.

schroeder
  • 125,553
  • 55
  • 289
  • 326
RobbB
  • 251
  • 2
  • 8
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.

schroeder
  • 125,553
  • 55
  • 289
  • 326
zivc
  • 1
  • 1
  • I would not go so far as to say that it causes harm, but it weakens this one helpful feature. – schroeder Jul 12 '22 at 23:24
  • 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 '22 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 '22 at 22:25
-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.

codetaku
  • 107
  • 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 '17 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 '17 at 17:16
-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.

schroeder
  • 125,553
  • 55
  • 289
  • 326
  • 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 07 '16 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 07 '16 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 07 '20 at 10:49