Fyi, there are some rather common formats to store salted password hashes - usually they don't even need multiple database fields. Usually it's something like hash-type$salt$hash (look e.g. at the hash bcrypt gives you)
–
ThiefMasterAug 16 '13 at 23:26

@ThiefMaster, gah that is totally it! It is all just stored in one field. If you want to post that as an answer I will accept. Thanks!
–
Abe MiesslerAug 16 '13 at 23:30

3 Answers
3

First of all, the passwords are stored safely (assuming the used hashing algorithm is safe) since the only plaintext thing is the salt which has to be plaintext - its only purpose is to prevent the final hash to be hash(password) since that would allow the usage of precomputed rainbow tables mapping hashes to passwords.

However, the way of storing them using two separate columns is not optimal. While somewhat easy to use when just passing salt and plaintext password to a hash function, most password hashing libraries use a better scheme. Let's have a look a bcrypt (or rather its python bindings for the sake of simplicity) which uses the same scheme as crypt(3) does.

As you can see, the resulting hash consists of multiple parts. First the 2aindicating the algorithm, then the "cost" used by the algorithm, then the 22-character salt (in plain text), then the actual hash.

The advantage of this is that checking the password can be done using the same function you use for hashing it - you just pass the full hash string as the salt and then check if it returns the same string. Another, more relevant, advantage is the fact that by storing it like this you can easily write a function to handle various hash algorithms by checking the first field. This is relevant when you have to deal with legacy passwords that were hashed e.g. using MD5 or SHA-1.

Some password hashing function traditionally encode the salt and the hash output as a single string, so the salt is there, but does not appear in the database as a specific column. Most bcrypt libraries do that. This might be the case for your system.

Also, the salt might be implicit (e.g. computed as the concatenation of the user name and a row ID, or something like that).

The salt must be known to verify the hashed password. There is no reason not to store it with the hash in the database as it is perfectly safe to be public information. It's purpose is only to prevent precomputer hashes from being used to rapidly find insecure passwords.