Salt and pepper at both client and server sides? Putting aside that it may sound paranoid.

I know that many users tend to use the same password on many sites. Then, from an ethical point of view, I should not only be concerned about security breaks that affect my own system, but also how my system might facilitate breaking the security of other systems.

Suppose that an attack allows a third party to read (but not modify1) the communication, including the password exchange during login. If they can read the user's name and password, they could gain access to the account of that person on other systems if they used the same name and password there.

To avoid that, I was thinking about doing hash(system_public_pepper+username_as_salt+password) at client side, along with bcrypt (which includes salt) with a secret system pepper. Both peppers would change at each server (randomly generated on install).

But then my new concern is whether this client-side hash could weaken the password (example: limiting the entropy).

And then:


What hash should I use to make sure there is no significant entropy loss? Is MD5 ok?
Can the pepper and/or salt weaken the entropy, considering it is of public knowledge (although salt changes between users)?
Does it make a difference whether the salt (username) or pepper (public) are prepended or postpended? Which order is best?

I think that if the salt or pepper are prepended, one can take the state of the hash algorithm at that point as a start, and then computing the hash of every password would cost less (as if there were no salt and pepper).

But, also, one could apply the same to common passwords if they are at the beginning.


Is there anything else I should consider?





Edit: I think that there is a misunderstanding from what I proposed. So, I will put an example. U is user, C is cliente, S is server, D is database (just pseudo for clarity, we can use PDO for prepared statements and so).

SIGNUP EXAMPLE:

C&gt;S: I need to signup, send me the public pepper.
S&gt;C: {"system_public_pepper":"Potts"}
U&gt;C: {"username":"johndoe","password":"IWasBornOn1987"}
C: P=system_public_pepper+username+password; //P="PottsjohndowIWasBornOn1987"
C: H=md5(P); //="28d36f3969e05dedb5f9ba20acd3842a"²
C&gt;S: {"username":"johndoe","hashpass":"28d36f3969e05dedb5f9ba20acd3842a"}
S: private_pepper="GwynethPaltrow";
S: new_pwd=private_pepper+hash_pass; //"GwynethPaltrow28d36f3969e05dedb5f9ba20acd3842a";
S: pwd_bcrypted=bcrypt(new_pwd); //"$2a$04$qh7z5sSkMCrLq6mrpdOwM.ohlvCKWvU3vQm.CrjrxcQc6otwByBle"³
S&gt;D: INSERT INTO users ('username','password') VALUES ('johndow','$2a$04$qh7z5sSkMCrLq6mrpdOwM.ohlvCKWvU3vQm.CrjrxcQc6otwByBle')


SIGNIN EXAMPLE:

C&gt;S: I want to sign in, send me the public pepper.
S&gt;C: {"system_public_pepper":"Potts"}
U&gt;C: {"username":"johndoe","password":"IWasBornOn1987"}
C: P=system_public_pepper+username+password; //P="PottsjohndowIWasBornOn1987"
C: H=md5(P); //="28d36f3969e05dedb5f9ba20acd3842a"²
C&gt;S: {"username":"johndoe","hashpass":"28d36f3969e05dedb5f9ba20acd3842a"}
S: private_pepper="GwynethPaltrow";
S: attempt_pwd=private_pepper+hash_pass; //"GwynethPaltrow28d36f3969e05dedb5f9ba20acd3842a";
S&gt;D: SELECT 'username', 'password' FROM users WHERE 'username'='johndoe'  //'$2a$04$qh7z5sSkMCrLq6mrpdOwM.ohlvCKWvU3vQm.CrjrxcQc6otwByBle'
S: password_verify(attempt_pwd,stored_hash)




Footnotes:


I know that it would be odd, since usually if you can sniff an HTTPS
communication, you can also run a MitM attack. But I was thinking
about a generic attack only aimed at reading because it may work on
a massive amount of sites. While modifying them would require more
work. So, at least I can prevent those. Also, I suppose it could be
a specific attack to the OS or HTTPS deamon that allows to read
communications.
Here is the key, the user password does not leave the client.
Let's say there is a bug at the server, and the received communications
get logged: you can't get the password logged, just the hashed version.
The stored hash is neither the original password, nor the received one.
I think the detailed approach you have given can work. To address your specific point:


Rule of thumb: No md5 is never okay, for anything.
I'm not sure what you mean but pretty sure that the answer is: No.
The order doesn't really matter although your point is correct and you should probably add field separators instead of just concatenating.


I think proposing this kind of change requires a consideration of the attacker model. Your connection should be secured by TLS and all this becomes moot.

You can do more advanced things, they are great but work a little different. Maybe looking Password Authenticated Key Exchange (PAKE) will give you some inspiration.