Salting Passwords - Security Series #4.3

My posts have been delayed a little this week. I was going to release this one yesterday, but my 16-month son came down with something bad and we were at the urgent care until 2AM. He is fine now, but at one point he had a fever of 105. Poor baby. So here we go with our next entry about password security.

What is salting?

So statisticians will sometimes ask you silly questions about Monty Hall and about Birthdays. The Birthday problem is the one that we are most concerned with as security professionals. The Birthday Problem states that if you compare the birthdays of 23 random people, there is more than a 50% chance that two of those people will have the same birthday. The reason this concerns us is because many knuckleheads use their Birthday as their password, or their PIN number. Other dates they may use are kids' birthdays, anniversaries, date they lost their... er uh.. wallet. Well, you get the idea.

So it occurs to password crackers that if people are using these dates for password, and if there are only 366 different dates then they could very easily make a hash look up table of all the possible date hashes. Additionally, if they did compromise a database and get a list of hashed passwords, they could look for duplicates and make a close to accurate assumption that they are likely dates. Even with all of the variations of date formats that people could enter, there are really less than 10,000 possible date passwords.

So what can we do about it? We can't stop the knuckleheads from using dates for passwords, can we? Well, actually, you could. I forgot to add a check to my post the other day to use the IsDate() function to give an error on a password if it returned true. But regardless, dates are not the only issue here, they are just a good example. There are other common passwords that could be placed into a hash table, like "123456" and "letmein" or any of the words in the dictionary. We can't check our users' input for every possible stoopid password they could enter. So what do we do when are users enter passwords that are likely to be found in rainbow tables? The answer to this issue is to salt the passwords.

Salting is the process of adding a random string of characters to the end of a user's password (or other sensitive data) before hashing it. Each password would get its own salt hence eliminating the problem of two like passwords having the same hash value.

Yay! More code!


<cfset val1 = "Password1" />
<cfset val2 = "Password1" />
    
<cfset hash1 = Hash(val1, "MD5") />
<cfset hash2 = Hash(val2, "MD5") />
<cfset hash1Salted = Hash(val1 & CreateUUID(), "MD5") />
<cfset hash2Salted = Hash(val2 & CreateUUID(), "MD5") />
    
<cfoutput>
Value 1 Hashed:#hash1#<br />
Value 2 Hashed:#hash2#<br /><br />
Value 1 Salted and Hashed:#hash1Salted#<br />
Value 2 Salted and Hashed:#hash2Salted#<br />
</cfoutput>

Will give us this output:

Value 1 Hashed:2AC9CB7DC02B3C0083EB70898E549B63
Value 2 Hashed:2AC9CB7DC02B3C0083EB70898E549B63

Value 1 Salted and hashed:2DEB5ADAF0854BBBC24DC4797BA73027
Value 2 Salted and Hashed:3498DD83CA3F1945D0EE7BE16984999E

Notice that when only hashed, the two identical values yield the same result, but when hashed and salted the two values yield very different results. This will help combat Birthday attacks, dictionary attacks, and other types of brute-force password attacks against your application.

But, wait. I'm confused again. If we salt every password with a random salt, how will we every figure out what the password was when it is time to authenticate the user again?

Great question. Huh, I hadn't considered that.

I'm kidding, I actually did consider that. The answer is that we store the salt. We put it in the database, probably in another table, and join it to the user. Then when the user send the password via the authentication form we append the salt to the user input and hash the value, then compare that to the hashed password value in the database. If the values match, the correct password was sent. We will cover how we actually do that in my next post, sometime next week.

Wait, wait, wait, wait, wait! Jason!? STORE the salt? What are you thinking? Isn't that just as bad as storing the password? With the salt in hand, the hacker would have half of the password, right? Couldn't they use that to hack our application?

Another great question. Geez, you are on top of this. The answer to that question, however, is no. In fact, the salt itself is really only being used to obfuscate the real password in its hashed form to prevent common passwords, like dates, "password", "123456", and the administrator classic "IamGod" from being found in a rainbow table attack. Gaining access to the salt list would get the hacker nothing more than he/she would get from performing a brute-force attack against your application via the login form. Heck, you could probably even put your salt list on your "About" page. Since a hash cannot be "reversed", having the salt will not give a hacker what they need to reverse engineer the hash into a real password with the salt appended to the end of it. Maybe somebody knows something about this that I missing, if so, please let me know, cause I want to be accurate. But based on what I know, the salt value is close to useless to a hacker.

Next week, I will be putting together a post that will demonstrate how to put these methods into practice with ColdFusion. Many of you will already be able to figure that much out based on what I have written so far, but for those that can't, or won't, I will have some sample code for you. We will also discuss storing the passwords.

Again, I will remind everyone reading, I REALLY want to encourage discussion here. If there is something I missed, or something you would like made clearer, please speak up. I get sad and lonely when no one comments ;)

Comments
joshua cyr's Gravatar

Great series by the way. For Salt, I have done two salts. one is stored in DB for each record the other is an application salt stored in code. So if they do get the DB and do find a way to rotate around each record to try to reverse something, they still don't have the app salt (unless they get the code too). As you mentioned it's most likely overkill, but takes 2 seconds to code so no biggie.

# Posted By joshua cyr | 5/22/08 8:30 AM
Laura Norris's Gravatar

Great series! I've been asked to give users the ability to change their passwords for our intranet and I'm going to implement hashing at the same time!



The current system is so bad that it stores the user's password in a session variable!

# Posted By Laura Norris | 5/22/08 9:16 AM
Jason Dean's Gravatar

Joshua - You're right! That's a great idea. Thanks for that tip. I recall talking about that with somebody in the past, and at the time the idea was shot down, but I think that is because the project manager had no idea what he was talking about.



I will add that to my list of (optional) best practices. Something that falls into that category of "overkill for some, but good for others".

# Posted By Jason Dean | 5/22/08 9:50 AM
Jason Dean's Gravatar

@Laura - Thanks! I'm glad to hear some of these ideas can be useful to others.



I have seen the password stored in session variables more often than I can believe. It's almost as bad as the cookie.isLoggedIn = "true" variable that is "oh-so-exploitable".



You bring up a good point to remember. There are very, very, very, very few reasons in web applications why the user's password would be required beyond the authentication stage. Most likely in a case like that, the developer designed the system to re-authenticate at the top of ever page with the user/pass that the user provided at login.

# Posted By Jason Dean | 5/22/08 9:54 AM
Craig's Gravatar Thank you for the post - has helped me in my understanding of salts and hashes.

One question would then be - if you were increasing security on a website built in asp classic, what would be the best way to retain the user's session once they have logged in? Obviously the IsLggedIn=true is a complete no-no but what would be the optimal? A sessionId passed in a querystring perhaps? Normal asp sessions? What if they have cookies disabled?

Perhaps a posted variable from each page? That probably would take too much coding to implement though.. not really practical. Looking forward to hearing your thoughts.

Cheers

Craig
# Posted By Craig | 2/11/09 6:30 AM
Craig's Gravatar (Apologies for the above post about asp classic on a coldfusion oriented site! I am sure though, that the principles are all-encompassing)
# Posted By Craig | 2/11/09 6:32 AM
Jason Dean's Gravatar isLoggedIn=true/false is only a no-no in a cookie. It is not a bad thing if stored in a session, as long as you can keep your sessions secure. That said, isLoggedIn should not be managing your session, only letting your application know that the session is logged in.

You session itself should be handled by the engine if that is possible. ColdFusion does a great job of handling this for us. I am not sure if Classic ASP does, If it does have internal session management and if that session management makes strong session tokens, then use that. But do some research first and find out if people think it is good or not. If not, then create your own session token cookie with a GUID in it and use that to maintain your sessions. In most cases, the only information that should be stored in cookies is the session token. Everything else should be stored in the session and the session token is used to connect that browser cookie with that session data.

Hopefully that makes sense.
# Posted By Jason Dean | 2/11/09 7:36 AM
Craig's Gravatar Thanks, all makes sense.

Cheers for the help!
# Posted By Craig | 2/11/09 8:32 AM
John Sieber's Gravatar Sorry for jumping in a few years late. These are excellent posts and I appreciate the time you spent to publish them. Just curious about the salt value. If security of the salt value is not that important, why store in a separate table?
# Posted By John Sieber | 4/22/11 12:54 AM
Jason Dean's Gravatar The salt does give the hacker additional information for developing a rainbow table, but the hacker would still need to develop a rainbow table of every possible password with that salt and for every possible iteration count (assuming you iterate the hash more than once, it's recommended you do it 1000 or more times). Even if the hacker obtains the salt, it is still a HUGE chore to brute force the hashes.

Now, as computers are becoming more powerful and cloud computing gives hackers access to super-computers for pennies it will become easier and easier.

Storing the salt in a separate table is an additional layer of security.

Another thing to consider is using something like BCrypt for your hashing. It actually slows down the salting and hashing process making brute force take longer (even on a super computer).
# Posted By Jason Dean | 4/22/11 11:55 AM
John Sieber's Gravatar Thanks for the detail answer to my question. Your blog is such a great resource!
# Posted By John Sieber | 4/22/11 2:15 PM
Jason Dean's Gravatar Thanks :)
# Posted By Jason Dean | 4/22/11 6:15 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner