Alternatives for sending plaintext password while login
I don't see to how your proposal is better than existing client side hashing approaches, but I find it as more complex to implement than others. Unfortunately you don't describe a specific risk you are trying to access so I just assume the typical threats commonly seen.
Man in the Middle attacker
In this case it is assumed that some man in the middle has access to the traffic, for example because it compromised some trusted traffic TLS interception in a corporate firewall or got hold on a trusted CA as in case of superfish.
In this scenario the attacker gets access to H
the same as they did before with plain_password
. Since H
is everything what is needed for authentication the attacker is thus successful and your approach does not add any additional protection here.
Hiding weak passwords and password reuse
A common argument for client side hashing is to not expose a weak or reused password to the server, but instead authenticate with a complex derived password. Your approach does this with hashing the plain_password
with some user generated random salt
and then send H
and salt
to the server on password setup.
While this works every authentication now requires an additional step: first it needs to retrieve the previously used salt for the user from the user and then it can use this salt
to hash the plain_password
. This additional step makes authentication more complex since first it needs to check the user with the server and later it can check the password. Additionally a trivial implementation of this opens an information leak since it makes it possible to check if the user exists in the first place (salt returned or not) without further authentication.
This information leak can be closed by the server returning some salt no matter if the user exists or not. Of course this cannot be just a random salt since otherwise an attacker could just check twice the same user and conclude that the user does not exist if the returned salt was different. So the salt actually has to be fixed for the non-existing user, i.e. derived from the user name.
And this also shows a path to simplify your approach: instead of generating a random salt by the user, storing it at the server and retrieving it later again, one could simply derive the salt from the user name at the client side. A simple salt=hash(username+domain)
would be sufficient to generate a salt which is unique per domain and thus make both salt
and H
different even if username
and plain_password
get reused on different domains. And contrary to your approach no additional trip to the server is needed to first retrieve the previously used salt for the user.
In short: this simplified approach is basically sending hash(plain_password+username+domain)
instead of the original password. The domain is added to make sure that even if username
and plain_password
are reused over multiple sites, the derived password is not reused.
This is exactly the problem that protocols like PAKE and SRP aim to solve. With PAKE/SRP, the client and the server mutually authenticate each other based on a password known to the client (and a derivation of the password known to the server).
The client demonstrates to the server that it knows the password, without the client sending the password (or password-equivalent data) to the server. At the end of the process, the client and the server share a shared secret.
The server does not store the password (or password-equivalent data) and is not susceptible to dictionary attacks. An eavesdropper or man-in-the-middle able to view the plaintext sent over the wire is not able to gain enough information to derive the password. This effectively prevents man-in-the-middle attacks using fake certificates, and prevents 'phishing' sites from stealing users' passwords.
For a good write-up of how 1password implemented SRP, see https://blog.1password.com/developers-how-we-use-srp-and-you-can-too/
In addition to the answer of Steffen Ullrich:
If during login the user sends the hash only, then the attacker does not need to know the password. It is sufficient to steal the password database. Then during login request the attacker will just send the hash from database. The server will not distinguish if client used the password and hashed it, or if the client (attacker) simply sent the hash.
The article about OPAQUE addresses also this problem: Stealing the password database will not help the attacker. One would need to know the plain user password.