28

So the traffic is encrypted to a website so the password is safe during transmission and also if the website is hacked then the database only contains hashes.

But couldn't the hacker create a server side script to store the usernames and passwords used to login to the website in a file since they are decrypted and are not already hashed? This wouldn't get every user however it would allow them to view users passwords who try to log onto the site while it is compromised.

Wouldn't it be better to hash passwords at the client side?

James
  • 281
  • 3
  • 3
  • 1
    No one will task about [SRP](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol)? It's important as it protects the password from the server without using *password-equivalents* and just have the problem that, without an native implementation by browsers (which [seems no one wants](http://stackoverflow.com/a/2842980/1850091)), it can be maliciously replaced, like happens with hashing. (*BTW, do you still support non-javascript users beside search bots? those bots don't login!*) – Gustavo Rodrigues Aug 13 '15 at 20:18
  • See [Digest Access Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication) – el.pescado - нет войне Aug 14 '15 at 08:38

5 Answers5

60

The weakness you allude to is real. An important point is that once the server is compromised, the attacker has little incentive to grab passwords that grant access to that server -- he is already in the place. However, human users have the habit of reusing passwords, and that is a big problem, because a reused password means that compromises on one server tend to "propagate", exactly in the way you explain: the attacker grabs password P for user U, and guesses (alas correctly, most of the time) that the same user U will have used the same password on some other servers.

Hashing client-side is a nice idea, but there are details:

  • Whatever the client sends to the server, be it the password itself or the hashed password, grants access. It is password-equivalent. If the server stores these hashes "as is" in its database, then it is in the same situation as a server storing plaintext passwords, and that's bad. Thus, the server MUST also do some hashing.

  • Client-side hashing occurs only if there is code on the client side that does the hashing. In a Web context, this means JavaScript. Unfortunately, JavaScript is poor at cryptographic implementations; in particular, it is quite slow, so the client-side hashing will not be able to use the many iterations that are usually needed for good password hashing (see this for details). Also, this would not work for clients without JavaScript.

  • Still in a Web context, the client-side hashing, if it occurs, is done by JavaScript code sent by the server. If the server has gone under hostile control, then it may send malicious JavaScript that pretends to do the hashing, but does not. The user will be none the wiser. Thus, the root problem is not solved.

Client-side hashing is usually envisioned under the name of "server relief", not to increase security against evil servers, but to allow the server to handle many concurrent users without spending all its CPU on a lot of hashing. JavaScript being what it is, this is not commonly done nowadays.

Thomas Pornin
  • 322,884
  • 58
  • 787
  • 955
  • 7
    You know, I just realized client side hashing actually makes some sense, because if the attacker wishes to retrieve the plain text passwords he will need to disclose the fact that he has compromised the server (change the source files) if properly monitored. It forces the attacker to do an active attack. Of course it won't help at all in *most* of the cases, but at least it does have theoretical benefits (I thought it didn't have any). – David Mulder Aug 12 '15 at 23:42
  • 3
    Client side hashing also helps with the problem of a user using the same password on multiple sites. From the standpoint of _password equivalence_, it may be true for this site, but that hash cannot be used for multiple sites (for instance if he domain name is involved in the hashing). – Frank Bryce Aug 13 '15 at 12:11
  • @DavidMulder Not really - if an attacker controls the server, they can redirect a request from your script to their malicious script in ways that undergo much less frequent and effective monitoring. No need to change the actual source files themselves, just supersede them. – Jason Aug 13 '15 at 12:23
  • @JohnCarpenter - Thomas talked some about why this is inadequate, client side javascript isn't fast enough to hash with adequate security, and hash-cracking these days is too advanced to rely on inadequate security. Ignoring that a compromised server need not tell the client to actually hash the password. A compromised server is the whole game, you can't do anything to save yourself. – Jason Aug 13 '15 at 12:26
  • 1
    @Jason Not saying that current monitoring already is sufficient, but at least it can be monitored. Just request a fair number of pages from your site and anytime it changes issue an alert to the head of development. If this lines up with a new version that is being pushed to production: Good. If not: Go and check. – David Mulder Aug 13 '15 at 12:27
  • @Jason Honestly, I have no idea where this believe comes from that you can't use a strong enough hash on the client side. Even if you opt for something like bcrypt as your hashing solution (which to be honest I wouldn't advice to most people) you still easily can run it with 4096 iterations if you want to (or even more if you *really* want to). – David Mulder Aug 13 '15 at 12:50
  • 1
    @Jason I'm not saying it's bullet proof, but then again nothing really is. My only point was that hashing on the client side would be another layer to make it harder for a malicious hacker to get passwords which may be used on other sites. And like David said, this would require an active attack rather than passive observation. – Frank Bryce Aug 13 '15 at 12:55
  • @DavidMulder So you're suggesting a single-pass message digest, like (for instance) Sha256? This is woefully insecure these days - any password hashing that is not designed to take large computing resources can be cracked swiftly and easily, most of the time in minutes or hours. And, having written a pure Javascript implementation of PBKDF2 for node and comparing it to the built in PBKDF2 from the crypto library, there's no way to use any number of iterations on the client that will use significant resources on the server (or on the attacker's machine). – Jason Aug 13 '15 at 13:29
  • @JohnCarpenter Beware "security" that seems to add steps to you that are really trivial for an attacker to overcome. They redirect your attention and activity away from things that really make a difference. – Jason Aug 13 '15 at 13:31
  • 1
    @Jason SHA256 is woefully insecure these days? That's just rubbish. Yes, if you have a password with very low entropy (a literal dictionary word), the hash has been properly salted, you know the salt and have a GPU to run the hashing then in somewhat reasonable time (a second or so) you will be able to find the password. But given a leaked database with SHA256 passwords where some of them have high entropy if you wish to crack all of (cont.) – David Mulder Aug 13 '15 at 14:22
  • them I will be waiting for you in a couple million years. I mean, hashing definitely has a place, but as long as the password isn't also used for encryption I would personally easily pick SHA256 or SHA512. Oh and, totally agree with your point in your last comment. Another reason indeed to just pick a normal hashing algorithm instead of messing around with a (client side?) dynamic increasing cost bcrypt solution. – David Mulder Aug 13 '15 at 14:22
  • 1
    @DavidMulder The *effective* entropy of passwords is decreasing at an alarming rate - what you consider "high entropy" may still be easily crackable due to the way humans construct passwords (see [this article](http://arstechnica.com/security/2013/05/how-crackers-make-minced-meat-out-of-your-passwords/)). If you're talking about a machine-generated random password then I agree with you, but that's still the exception rather than the norm. – Jason Aug 13 '15 at 14:31
13

So there's two separate parts to this.

First, the server getting compromised, and second, sending hashes to the server instead of passwords.

For the first part with the server getting compromised, yes, the attacker could pretty much do whatever they want. If they own the server, they can indeed get the usernames and passwords from the users being passed to the server. This is why servers need to be hardened against attacks and regularly updated so that they offer as little of attack surface as possible.

For the second part, if you have the client pre-compute the hash, then that hash has literally become the password. If an attacker were to have stolen the database of hashes(but hasn't compromised the web server), he doesn't need to find the passwords that turn into those hashes; he can just send the hash to the web server, and it would authenticate since the server would already be expecting a hash as input to compare against its database.

Greg
  • 869
  • 7
  • 10
  • 5
    Yes, but on the other hand, the point of hashing passwords isn't to protect users' access to that site. (If you pwn the database, you can copy all of the users' data anyway; you don't *need* their login credentials.) The point of hashing passwords is to protect all those poor idiot users who use the same password everywhere, so that the hackers don't have access to the entire rest of their online identity. – Mason Wheeler Aug 12 '15 at 21:10
  • 2
    @MasonWheeler That assumes that the attacker's only goal is to access data which is stored in the database. What if his goal is to access a CMS and deface webpages, or delete user accounts by logging in as an admin? – Cat Aug 12 '15 at 21:32
  • @Eric if I pwn the database, couldn't I (1) make a copy of the user's hashed password, (2) pick a new password, (3) computer the hash of the new password, (3) replace the user's hashed password with my hashed password, (4) authenticate as the user, (5) do whatever I want, (6) replace my hashed password with the user's hashed password so the user won't know I changed his password. – emory Aug 13 '15 at 00:11
  • 1
    @emory If you have write access to the database, yes. – Cat Aug 13 '15 at 00:18
  • 2
    Bear in mind that a common scenario for illicit access is attacker access to backup media.  (I've heard stories of backups being thrown out in the trash/recycling.)  If the site doesn't have an aggressive frequent-password-changing policy, an old backup of the password (hash) store may still be highly current.  This and other scenarios may lead to a one-time read-only access to the password data (e.g., a zero-day code injection attack against the login program may yield that, and only that, without providing broader access to the site). – Scott - Слава Україні Aug 13 '15 at 05:07
1

You likely wouldn't be able to prevent simple server-side modification of the code sent to clients to execute if your server is totally owned.

However if this is part of a pre-installed or pre-distributed software package with distinct client and server components (this could include web applications with downloaded components that stay resident on the client OS), client side hashing could be useful in the sense that, while the attacker can likely still use those hashes for authentication to YOUR database (or just reset passwords as mentioned in one of the comments), they no longer have easy access to the plaintext password that would be sent to your server (over SSL) for salted hashing and database storage.

So, if you have a client using the same password in multiple places, so long as the hash isn't trivially reversible, your particular server compromise has no longer disclosed credentials the attacker can use elsewhere. This would be enhanced with random client-side salting (so that you're not ending up with the same hash that the same algorithm would always generate for that plaintext).

Bruno
  • 303
  • 1
  • 5
1

I find a lot of people (especially in the PHP realm) misunderstand what hashing does. Here's the methodology

  1. User creates account and sends a username/password combo to you (securely over HTTPS I hope)
  2. Password is hashed on the server (with a random salt) and stored with the username
  3. User comes back later and enters their plain text password
  4. Server finds the stored hash for the username. With $2y hashes (BCRYPT) the cost and salt are stored in the same string. So using the same cost and salt, the server generates a hash using the user provided password (remember, hashes are one-way by design)
  5. With everything being the same, if the generated hash matches the stored hash, we can authenticate the user

Assuming that someone hacks your server your users are better protected because the salt is random for each hash. As such, you would have to brute force each password separately (the core theory behind any type of security is to raise the cost of doing something to the point where someone will not attempt it). SHA1 and MD5, the previously popular hashing systems, were almost always generated without any salt, making them susceptible to not only any weaknesses in the hash itself, but rainbow table attacks (without salt each SHA1 and MD5 is the same for a given string).

There's really no way to do this client side because

  • The client is in the hands of the enemy. So you would have to send the client everything they need to generate the hash (most notably the salt) and then have them pass back the hash.
  • As mentioned in another answer, at that point their hash becomes the password because that's what they send to you. In other words, even though I might not know what the password is, you're still doing simple string comparison instead of generating a secure hash so I can break in
Machavity
  • 3,808
  • 1
  • 14
  • 31
-2

No, Inspect Element or something similar exists on most browsers, allowing anyone to bypass client-side code. If a hacker got access to the database, they could remove the hashing code using Inspect Element and enter the hashes as passwords, or edit the page to not hash it anyway. How about instead, a script that stops the server if it senses a page has been modified by a hacker?

Lucas
  • 105
  • 1
    "inspect element" is not what you were going for – schroeder Aug 13 '15 at 22:28
  • Having access to the code which performs the hashing isn't enough - you still need to know what was input into the algorithm to generate the hash. Also, how would you implement a system to detect a page which was modified by a hacker from a legitimate modificaiton or deal with dynamic pages? – Tim X Aug 13 '15 at 22:49
  • This makes no sense. If a hacker got access to the server, they still cannot use "inspect element" on any clients than his own. – Bergi Aug 14 '15 at 09:20