You need something like Secure Remote Password Protocol (SRP). As pointed out by Earendul and André Ribeiro, simply moving the server hash pro client negates all security benefits - because an attacker who obtains a copy of the BD can simply use the stored hash to log in immediately as any user (since the access pass becomes the hash, not the original password). Requires a protocol whose security features remain even with the hash on the client side.
And that protocol is SRP. The original protocol has a weakness (weakness that remains present in the standard SRP implementation via SSL/TLS), which is the use of a simple SHA-256 as a hash function, rather than a slow function like Bcrypt. So you would have to implement yourself in the application layer and/or get a secure implementation in the same way.
It’s a little bit more complicated than most protocols - because it involves multiple messages coming and going between the client and the server. There are also some parameters to be established, see the indicated reference for more details.
To register a new user:
- The customer whose password is
p
, choose a random salt s
and calculates the hash x = H(s, p)
; calculates also v = g^x
, where g
is a common parameter between the server and the clients.
- The server stores
v
and s
associated with username of that client. x
is discarded - so that even if an attacker copies the BD, he will not know the result of the hash.
For an existing user to log in:
- The client chooses a secret key
a
random (and ephemeral) and sends A = g^a
to the server (plus your username);
- The server also chooses an ephemeral key
b
, calculates B = kv + g^b
(k
is a parameter independently calculated by both parties) and sends B
and s
for the client;
- Both calculate
u = H(A, B)
;
- The customer calculates
Sc = (B-kg^x)^(a + ux)
and K = H(Sc)
, making use of your password again p
to obtain x
;
- The server calculates
Ss = (Av^u)^b
and K = H(Ss)
.
Now both the client and the server have a secret and shared key (and ephemeral), derived in part from the user’s password. It remains only for each of them to prove to the other that they have achieved the same result:
- Client sends to server
M1 = H(H(N) xor H(g) | H(I) | s | A | B | K)
, and the server checks using its K
. |
means the concatenation of strings. N
is another common parameter between client and server, and I
is simply the username.
- Server sends to client
M2 = H(A | M1 | K)
, and the customer checks using its K
.
Source: Wikipedia
This is the original protocol, which uses SHA-256 as a hash. As you can see, it is used several times during the protocol, so that it is impossible to replace it with a slow hash in all its uses - when all you want is to protect the password. A preferable option - as pointed out by Tom Leek no security.SE - is to maintain the identical protocol, only apply p = BCrypt(s, p)
in the password before using it (you can use the same salt s
, but if feasible it is preferable to use a salt s2
- if your implementation gives support of course). Thus you gain the hash protection without increasing the server load.
An attacker who gains access to the comic will only see s
and v = g^x
, so that he would have to compute x
to be able to log into the server ("simulating" the protocol offline). And how to get in x
he would have to redo the hash slow, the protection of it is ensured.
Perhaps it is more advantage to use SSL (HTTPS) than to implement all this on the client side. Sending the hash to the server will be basically the same thing as sending the password. If someone intercepts this hash, all they need to do is resend the hash to authenticate.
– André Ribeiro
@Andréribeiro If I understand your placement correctly, I think you are mistaken, because the password verification is based on the original password, typed by the user. What Rodrigo wants, I believe, would only generate the hash when registering the password. But I could be wrong, because it was not specified if it is for the login or registration...
– Oeslei
@Andréribeiro is right, no matter if an access credential is a "password", "key", "hash" or anything else - if presenting that to the server authenticates you, then the attacker only has to get hold of that to gain access to your account. The defense (i.e. the slow hash) then has to be applied to that in order to keep the original credential out of the BD.
– mgibsonbr