7

If the password is hashed and then sent to the server where the hash is compared to the stored hash, this basically means that if someone had that hash they can still log in by sending the hash in the request, the password is just useless at this point.

I am talking with respect to Bitwarden. How does hashing a password make it more "secure"?

Fire Quacker
  • 2,442
  • 1
  • 21
  • 29
raptorAcrylyc
  • 221
  • 2
  • 5
  • 2
    Does this answer your question? [Hashing Passphrase in Client-Side JavaScript Rather than Server-Side -- Is it Viable?](https://security.stackexchange.com/questions/50909/hashing-passphrase-in-client-side-javascript-rather-than-server-side-is-it-vi) – forest Apr 09 '22 at 17:58
  • it's mostly theater since TLS is in play anyway, but it does provide a chance for the user to provide slow hashing work instead of the server. – dandavis Apr 10 '22 at 09:11
  • 1
    I *honestly* can't tell if this is a troll question or not. OOH, the 'why' of hashing is well-covered turf, OTOH it involves a fundamental (and still technically theoretical) asymmetry, and asymmetries can be hard to grok. – Jared Smith Apr 11 '22 at 12:15

6 Answers6

27

If the password is hashed [locally] and then sent to the server where the hash is compared to the stored hash ... I am talking with respect to bitwarden

This is not how it is done. From Bitwarden help:

Bitwarden salts and hashes your master password with your email address locally, before transmission to our servers. Once a Bitwarden server receives the hashed password, it is salted again with a cryptographically secure random value, hashed again, and stored in our database.

So basically the locally hashed password is treated as the server visible secret and this is properly protected with server side hashing.

The point of local hashing is that the password that the user can remember is never transmitted, i.e. it is an additional security measure. While it is true that the resulting hash would be usable by an attacker instead of the original password, it is much harder to guess the long and kind of random hash than the way more weak password. And brute forcing this original user password is also made harder due to a deliberately slow hash function. What Bitwarden does here to harden a weak password is also known as Key stretching.

kelalaka
  • 5,474
  • 4
  • 24
  • 47
Steffen Ullrich
  • 190,458
  • 29
  • 381
  • 434
  • 4
    Thanks for the reply, still, the hashed password that is transmitted holds the same value as a password, how does it make a difference assuming this password is not used on other websites? – raptorAcrylyc Apr 09 '22 at 09:39
  • @raptorAcrylyc: I've updated my answer with more details. – Steffen Ullrich Apr 09 '22 at 09:50
  • 4
    Password managers typically use the user's password to derive a key, which the server must never be able to access or derive. Therefore, the material used to derive the key - the raw password - can't be sent to the server. Client-side hashing (using a different algorithm, or at least a different salt, than the key-derivation process) is a way to achieve this. In other words, the password is hashed in two ways: one for authentication (goes to the server), and one for key derivation (client only). The server never sees the raw password so it can't get the client-only key. – CBHacking Apr 09 '22 at 09:52
  • @CBHacking Generally it is just a different number of rounds of the same algorithm, but yes that is the main reason client side hashing is used: to enable both key derivation and user authentication from the same password without violating the zero knowledge architecture. – nobody Apr 09 '22 at 10:10
  • 2
    @raptorAcrylyc remember that we use TLS to secure the transmission... – kelalaka Apr 09 '22 at 13:06
8

I don't know much about Bitwarden, so this is a general answer.

Taking from Steffen Ulrich's answer though, let's analyse this flow:

  1. User enters password in his application
  2. The application hashes the password
  3. The hash is sent to the server
  4. The hash is hashed again and compared to a stored hash-of-a-hash-of-a-password.

I'm omitting parts like salting and the choice of the hash algorithm, because all that they do is just make bruteforcing (aka guessing all possible passwords to find one that matches a hash) harder. We'll assume that the hashing algorithm is good enough that bruteforcing is infeasible.

So what's the reason for hashing at points (2) and (4)?

The hashing at (2) is done to remove the actual password from sight. People often do use the same password on multiple websites, so we want to do all that is possible to prevent hackers from seeing them. Even if our website gets compromised, at least we can protect our user's accounts on other websites. By hashing it already at (2) we ensure that no matter what the hackers might have compromised further down the line, they will NEVER get to see to the actual password.

Of course, if they have compromised your computer and installed a keylogger, then you're doomed. 100% security is impossible. But other parts of the system can be protected. And for hackers it is more efficient to go after servers, which are central points where 1000's of users connect to, than to try and hack 1000's of user computers (although the latter can be somewhat done with viruses and phishing).

Anyways, back to our scheme. So the point (2) is clear - but then why (4)? Precisely because of what you observed - that if someone gets their hands on the hash from (2), then even if they don't see the actual password, they can at least get access to THIS system. The hashing at (4) makes that harder, because it removes one place where the hashes from (2) could be found en masse - the database which stores them. Servers can and do get hacked, and every so often a hacker finds themselves with access to some database. Maybe it is the live production database, maybe it is a backup copy, who knows. The point is - if we do step (4), then the hashes from (2) won't be there. Only hashes-of-hashes. And you can't use those to log on to the system.

Of course, if you have access to the database, then maybe you don't care about knowing the hash from (2) anymore... Or maybe there is still something that cannot be accessed without knowing it. For example, you could encrypt some data by using the hash from (2) as a key.

Vilx-
  • 998
  • 2
  • 7
  • 15
  • You're normally correct about salting, but it's critical for the scheme you mention up top. Let's say you connect to two sites, AAA and BBB. We'll say that the password is hashed into hash1, and hash1 is hashed into hash2. A major point of local hashing is so that someone listening in on the communications between the client and server can't get the password. If there's no salting in step two, then the attacker might be able to use hash1 from the connection to AAA, as a "password" to connect to BBB. This is because hash1 is the same on both servers, if the password is not salted. – Patrick M Apr 10 '22 at 18:33
  • @PatrickM - Hmm... am I correct that the salt is given by the servers and then used by the client to hash the password? – Vilx- Apr 10 '22 at 20:46
  • The salt has to be the same each time or the hashes won’t match. As long as both clients aren’t compromised, it doesn’t matter, since they’re determined at password change, not login time. And if both clients are compromised, it doesn’t matter, since compromised clients can steal the passwords anyway. The “salt” used for the first hash has to be public, since it’s used by the client before you authenticate. For that reason, I might use a public deterministic function, based off the username. That way it won’t leak public information. – Patrick M Apr 11 '22 at 00:11
  • (Cont) Then you can even give salts for users that don’t exist to avoid revealing if user exists. – Patrick M Apr 11 '22 at 00:11
  • @PatrickM Clever! I like that! Hmm... That makes me wonder - Should this be a best practice for websites? Or would it be pointless, because if an attacker ever comes to a point where this defence would make a difference, they already can bypass it anyway? – Vilx- Apr 11 '22 at 00:34
  • As you suggest, it won’t help if the client is compromised. For a website, the client is Google Chrome, together with the JavaScript the server sends. So, it will help if the attacker can evesdrop, but not if the attacker can change things in the encrypted stream. (You‘d better be using SSL or you have bigger problems). So it protects against password theft due to Heartbleed. I would expect it is one of those things that is useful, but not useful enough to be widely used. So this might be useful, but better 2factor auth or passwordless authentication is probably better to work on. – Patrick M Apr 11 '22 at 02:54
1

this basically means that if someone had that hash they can still log in by sending the hash in the request,

No this is a misunderstanding because you're forgetting that the program or app process is the same regardless of the input. This means if you send a hash as input it will be hashed again creating a completely different value. You would have to separately compromise the application or server in order to do what you are imagining.

On a deeper level it also helps programmatically in making the data input uniform in size and things like that which is why computers do it all the time.

mh61
  • 23
  • 1
  • 1
    The question refers to client-side hashing, and the attacker calling the server directly (bypassing the client application). Naive client-side hashing -- i.e., not salting with a temporary token, etc. -- is indeed vulnerable to replay requests in this manner. – Matthew Read Apr 11 '22 at 20:00
1

The point is to not be storing or transmitting passwords in plain text. This is basically it. Everything else is all about making it hard to derive that text or other text that will achieve the same end, otherwise we would just use CRC-16 an be done with it.

Where this falls over is that storing a hash digest where people have access to both the digest and the hash algorithm becomes a risk.

So generally it is encrypted at rest after multiple rounds of hashing and salting, and there is minimal access to the encrypted data.

Frankly the encryption and vaulting is more important than salting and hashing. Given 30 million hashes it is trivial to group and sort the duplicates, and we pretty much know what the top 50 will be.

But really - not plain text. That is all. Not to prevent index hotspots or file splitting, but plain text. In the days of FTP an Telnet and Kermit we did not have SSH, or SSL, or IPsec.

mckenzm
  • 487
  • 2
  • 6
1

I think the other answers do not properly address your question about the risk of an attacker re-using the hash that the client sends. Therefore:


While the hashing prevents the server from ever knowing the plain password, your point is absolutely valid: it does not prevent a malicious re-use of the hash. If the client-side generated hash is used again, that is referred to as a replay attack.

This can be avoided by adding a session token, which is randomly generated by the server and sent to the client with the login request. The session token can be used as a salt to hash or encrypt the transferred value. (In this case, it would be encrypt, because it needs to be reversible by the server.) See Prevention and countermeasures in the Wikipedia article for details.

If an attacker then gets hold of the transferred value, it is useless, because if they open a a login request, the server will generate another session token.

For clarification: this would have to be an additional measure on top of rather than instead of the existing hashing.

Does Bitwarden use a session token?

Searching the Bitwarden online documentation, I wasn't able to find out if Bitwarden uses this technique. Instead, I found this reddit thread which actually supports your concerns.

Yet, note also that Bitwarden offers two-factor authentication (2FA), which mitigates the risk of a replay attack significantly.

not2savvy
  • 711
  • 5
  • 12
  • 1
    How is the server supposed to verify the password if the salt changes every time? Or are you trying to propose a challenge-response mechanism (in which case your current description is not sufficient)? – nobody Apr 10 '22 at 10:43
  • TLS is absolutely sufficient to protect against a replay attack. If you say otherwise, please show how. – nobody Apr 10 '22 at 10:47
  • 1
    @nobody As my answer says, the session token can be used to hash *or* encrypt the value. In this scenario, the latter would be the case. Updated my answer accordingly. – not2savvy Apr 10 '22 at 10:51
  • Encryption is entirely useless. You already have encryption at the TLS layer. Also, the entire reason Bitwarden is hashing the password client-side is so that the server *does not receive the password*. Encryption also defeats that goal. – nobody Apr 10 '22 at 10:55
  • 1
    @nobody Re TLS: this is exactly what the question is about. If an attacker gets hold of the transferred hash, it could re-use it. The secure connection channel doesn't make a difference in this case. I'm not questioning TLS as such, it's on completely different layer. – not2savvy Apr 10 '22 at 10:55
  • 1
    I'm not saying that encryption with a session token would replace the existing hashing, but used on top of it. Updating my answer. – not2savvy Apr 10 '22 at 10:57
  • Sure they could replay it. And the correct answer to the question is that the purpose of the clientside hashing is not to prevent someone from replaying the password, it is to make sure the server doesn't receive the password for reasons [explained by CBHacking](https://security.stackexchange.com/questions/261064/whats-the-point-of-password-hashing/261086#comment539910_261065). Your homebrew scheme will do very little to add any security to the system. – nobody Apr 10 '22 at 10:58
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/135443/discussion-between-not2savvy-and-nobody). – not2savvy Apr 10 '22 at 11:01
  • 1
    Perhaps the question just has two aspects: does the hashing prevent a replay, and if no, what is its purpose then. Considering this, two different answers to each of these aspects may be appropriate. – not2savvy Apr 10 '22 at 13:06
1

Based on the elaboration in the answer by Steffan that both client and server do some hashing, there are a few notable security advantages to doing it this way compared with just sending the password.

  • It demonstrates safety from password stealing. Yes, an attacker breaking into Bitwarden's server would have difficulty getting the password back if Bitwarden are doing all the hashing stuff correctly, but that's an if. This moves some of the best practice to the client-side, so you could confirm that if.
  • It provides safety even from Bitwarden stealing your password. Which is a bit of a funny thought, especially about Bitwarden given they have all your other passwords! But in general, hashing and salting server side only protects your passwords at rest. Doing it this way this means that even if a rogue employee added "Email me everyone's password" to the login script, they still couldn't try that password against your bank.
  • It provides some further security in transmission. For example, even talking to a server with an encrypted HTTPS connection can still reveal how much data you're sending. That means a snooper might be able to distinguish whether you use a long or short password. Hashes, however, are fixed length so there's no possible length-based information loss here.
Josiah
  • 1,848
  • 9
  • 14