Using our current scheme, the digests created by the client are stored directly in the database. Now, if hackers were to gain access to the database server, they would be able to authenticate as any user. Furthermore, since the attacker would have both the digest and salt, they could potentially brute-force a user's password.
One way to mitigate this issue is to use a pepper—a variation of a salt, with the following differences:
- The pepper is not public
- The pepper is not stored in the database, but on another application server, so that the pepper is separate from the salt
- The pepper may be a constant that's set in the application server as an environment variable
Here's how the authentication method would work with the pepper: the client sends the salted password digest to the server, who hashes the digest again with the pepper and stores the double-hashed digest in the database.
Now, if a hacker were to gain access to the database server (but not the application code), he/she will have the password digest and salt, but since he/she does not know the pepper (or, better still, even of the existence of a pepper), he/she would not be able to use the digest to authenticate (because our server would hash it again, and the resulting hash would not match the digest we have in the database). Furthermore, the attacker won't be able to derive the original password, even if they spent the time and resources to brute-force it.
However, peppers are only useful if your application server is secure. If the secret pepper is ever known, it cannot be retracted, as all our passwords were hashed with the pepper; since hashing is a one-way process, we cannot regenerate all password hashes with a new pepper. The inability to rotate this secret pepper makes this type of pepper unmaintainable.
An alternative to this is to not re-hash the salted password digest, but use a reversible block cipher to reversibly encrypt the digests instead.