What are the security implications of multiple hashing? There are plenty of questions on this site about hashing passwords. However, none of them quite cover this topic. One of those links covers using multiple different hash algorithms; one covers general hashing, and the other covers how passwords should be transferred. However, I want to know what the security implications of using one hash function multiple times.

I came across an article a while ago saying that this is not a good idea. However, I want some definitive answers. So, what are the security implications, good or bad, of using a hash system like this:

hash(hash(hash(password) + salt) + pepper)


In other words, hashing the password, then hashing the hash of the password with the salt, then hashing this hash with the pepper.
Multiple hashing, in itself, is not a bad idea.  What's bad is trying to design your own non-standard password hashing scheme, without understanding what features such a scheme needs in order to be secure.

In fact, hashing the password many times can be a very good idea, as long as you do it sufficiently many times.  This is one way to slow down the hashing process, and so make it more resistant to brute force cracking attempts, a technique known as key stretching.  This is something any good modern password hashing scheme should do, and the way many such schemes, like PBKDF2, do it is, in effect, by hashing the password many times.

As for your example of hash(hash(hash(password) + salt) + pepper), this will not, in general, be any weaker than just hash(password + salt + pepper), but it's also not significantly stronger.  To achieve any kind of useful key stretching, you need to iterate the hash at least 1,000 times, and preferably closer to 1,000,000 times (or however many iterations the user is willing to wait for).



Ps. For anyone thinking of designing their own password hashing scheme, or evaluating the security of an existing scheme, here's a quick checklist of the properties such a scheme should, at a minimum, have:


It should not be possible to reconstruct any information about the password directly from the hash.  (This is a very basic requirement.  Even a single application of any cryptographic hash function, like the SHA-2 functions, is enough to ensure this.)
The hash should accept arbitrarily long passphrases, and should depend on every bit of the passphrase.  (Again, this requirement should be obvious, but some very old and/or very badly designed hashing schemes like DES-crypt may fail it.)  If, for the sake of usability, some features of the passphrase (like surrounding whitespace or letter case) are deliberately ignored, the user should be clearly informed of this before they select their passphrase.
The hash should be salted, so that two users having the same password will not get the same hash.  Ideally, the salt should be globally unique and unpredictable; it should certainly not be just the username.  A sufficiently long random string (e.g. 10 or more base64 chars) is OK, but ideally the salt should also comprise other hopefully unique elements (like, say, an SHA hash of the username, server ID and a timestamp) to ensure uniqueness even if the random number generator fails.
In addition to the salt, the hashing scheme may depend on a secret key (sometimes called "pepper").  However, its security should never depend solely on this key remaining secret.
The hashing scheme should be resistant to brute force attacks, meaning that the hash should be slow to compute.  This can be achieved by iterated hashing, as described above, or by other constructions designed for the purpose (as in scrypt).  The slowness should be controlled by an adjustable parameter (and, ideally, should adjust itself to available hardware).  In particular, there should not be any "shortcuts" for checking the validity of a password significantly faster than by the standard method your code uses.  If possible, the hashing scheme should also be designed to be unsuitable for massively parallel implementation (e.g. on a GPU; scrypt is designed like this, PBKDF2 is not).  Also, if possible, in client&ndash;server applications, most of the hashing effort should be offloaded to the client (but the server-side part of the hashing scheme should still be secure by itself, even if the client misbehaves).
The users should be encouraged to choose long, randomly generated but easily memorizable passphrases (such as those generated by diceware).  To that end, the user interface may automatically generate and suggest such passphrases to the user.  (If so, care should be taken to ensure that the random number generator used is of high quality, and that the passphrases cannot be captured by an attacker.)  The user should not be forced to comply with inefficient and artificial requirements like "password must contain at least one number", although passwords using a diverse set of characters (including non-ASCII Unicode characters) should certainly not be forbidden (or, worse yet, stripped of such characters).