First "Do Not Create Your Own Password Storage & Verification" (unless you 'Know' what you are doing) instead of using an already established and proven library or algorithm and 'scheme'. But let's say you are using PBKDF2-sha256 which is very good, but like me you don't like how it stores the Salt in the database along with the hash and iterations. Well, on a project where I beefed up password security, on a 10+ year old website; the client's on staff developer came up with what I consider, one of the best Salt storage ideas. Then it was my job to make it real, and make is fast enough for production use. (I am not covering basic password security concepts here, just a slight modification, to increase complexity of obtaining all the data to compromise a users password)
I am of course talking about Pre-Shared Salt files, to all webapp servers. This is more secure than one might think. Lets look at a few examples of password storage which is used for hundreds of thousands if not millions of users' passwords, across multiple application and service providers.
A Single In-App Salt.
In some cases the developers used a single Salt for all passwords, hard coding the Salt into the Applications source code. While this offers obscurity, since the acquisition of the database alone, does not reveal the Salt, it is rather week, as only one salt needs to be discovered, to then figure out all of the passwords
Salt stored on the Password hash result (POPULAR)
While I understand that, this is rather impractical to break, especially at a large scale. The idea of storing the "Salt : Hash : Iterations : Algorithm" together in a single string, separated by a special character, just doesn't sit well with me. Many times you will hear security experts say something close to "Your only as secure, as the distance between your Keys, and your Data". Meaning, don't store your encryption/decryption keys, in the same record, as the data you are decrypting; try to not even keep them on the same server.
This is by far the most popular scheme I have seen in open source, and proprietary code. There are libraries put together to assist in making this simple. Python has one of the better PBKDF2 libraries (for simplicity of use at least) I have seen.
Adding some distance to Salt and Hash
For a client, which I assisted in taking their single server app and changing it to have a WebApp cluster, and a Database cluster, topology we discovered several security issues with their password validation and storage scheme. After which I strongly recommended that this was the very next priority on the list. We decided to use an existing scheme which has a unique Salt for every Password, with a slight alteration. We didn't want the Salt and the Hash result to be stored together. But then where do we store the hash? How do all of the webapp servers know the salt? We decided to pre-calculate all of the salts for all users now and into the future (up to a limit) and create a large binary file. This file is stored on each webapp server. (if our database is compromised, they will not have the salt of the passwords) This satisfies my desire to add distance between the hash and the salt.
How does it work?
First the bullet point outline:
- Have a random byte file (32byte * num_users) created, and distributed to all webapp servers
- On password_hash create
- Get user_id, to use as (32 * user_id) = salt_start_byte
- open file and seek to salt_start_byte
- read 32 bytes into salt_bytes
- Create password hash using salt_bytes, password, iterations, & algorithm
- Store the Hash + iterations + algorithm (hashset) into a string and into your database (maybe obfuscate it if you would like, this might hide some of the obviousness of the systems process)
- On validate password:
- Get the user record/data
- Obtain the salt from the file (on the local webapp server) using the same index used above
- Read the stored hashset result from database (splitting our the data parts)
- Using the data parts, recreate the password hash
- Compare the new hash to the stored hash
In this workflow, you get at least the same security as the current standard. However, I believe you are significantly increasing your security. This is due to the distance between the needed parts, to validate the correctness or a password (which is the only way at the moment to hack a one way hashed password)
Given the computational load of generating these hashes, it is unlikely that they will be "hacked" (via brute force) with our current computer technology. But even if the computational capability exponentially increases in a short time; by storing a piece of the needed data, on a completely different server, than the result; it will be nearly impossible, to brute force that even with quantum computers (maybe?)
Think about it like a math equation, Solving for X (one variable) is rather easy. But solving for 2 (X and Y) is orders of magnitude more difficult. Especially if you are not given any constraints about the possible value of X or Y.
My Conclusion Is,
I really think that all developers working on a login and our authentication system, should consider the possibility of splitting the salt from the hashset and pre-sharing it across all the webapp servers. Decreasing the chance a hacker obtains all the information needed, to "brute force" (or dictionary attack) the data, retrieved.