Salting and Hashing Code Example - Security Series #4.4
So let's create some code for salting and hashing password. What I have here is a function that will take in a username and a password and return, the username, a hashed password, and the salt. The idea is that after the function creates these three things it can then pass that struct (or object if you swing that way) to the next method (or DAO) for insertion into the DB.
So we'll start with a quick method stub. We are going to create a simple method that takes in the username and password as a string and it will return a struct. Right now we are returning an empty struct, but I bet we can fix that.
<cffunction name="hashPassword" access="public" returntype="struct" output="false" hint="I will add a user to the database and return a boolean to let you knwo if it suceeded">
<cfargument name="username" type="string" required="true" hint="Pass in username" />
<cfargument name="password" type="string" required="true" hint="Pass in password" />
<!--- Return var --->
<cfset var returnVar = StructNew() />
<cfreturn returnVar />
</cffunction>
We'll create our local variable for storing the hashed password while we work with it
<!--- Initialize Password Hash variable --->
<cfset var passwordHash = "" />
Now we'll create a salt. I like to use the CreateUUID function. It's long enough and random enough that it makes a great salt.
<!--- Salt the password --->
<cfset var salt = CreateUUID() />
Finally, we'll concatenate the password that was passed in with the salt and hash it.
<cfset passwordHash = Hash(arguments.password & salt, 'SHA-512') />
But wait! What's this? I did not mention this part in my previous posts.
<cfloop index="hashCount" from="1" to="1025">
<cfset passwordHash = Hash(passwordHash & salt, 'SHA-512') />
</cfloop>
Because we want to make our hackers' lives difficult, we are going to iterate over the hash 1000 or more time. If they are going to be hashing common passwords and sending them to the front end login page or remote login service in a brute force attack on our application, We want it to take 1000 times longer than it would if we did not do this. Your users won't notice the difference. This entire method took
Now we insert the values into the return struct and return it to the calling function or page (or if we wanted to we could pass it onto the next function).
<cfset returnVar.username="#arguments.username#" />
<cfset returnVar.password ="#passwordHash#" />
<cfset returnVar.salt = "#salt#" />
<cfreturn returnVar />
Here is the full code.
<cffunction name="hashPassword" access="public" returntype="struct" output="false" hint="I will add a user to the database and return a boolean to let you knwo if it suceeded">
<cfargument name="username" type="string" required="true" hint="Pass in username" />
<cfargument name="password" type="string" required="true" hint="Pass in password" />
<!--- At this point the function assumes that you have already validated the username and password as meeting application requirements --->
<!--- Return var --->
<cfset var returnVar = StructNew() />
<!--- Initialize Password Hash variable --->
<cfset var passwordHash = "" />
<!--- Salt the password --->
<cfset var salt = CreateUUID() />
<cfset passwordHash = Hash(arguments.password & salt, 'SHA-512') />
<cfloop index="hashCount" from="1" to="1025">
<cfset passwordHash = Hash(passwordHash & salt, 'SHA-512') />
</cfloop>
<cfset returnVar.username="#arguments.username#" />
<cfset returnVar.password ="#passwordHash#" />
<cfset returnVar.salt = "#salt#" />
<cfreturn returnVar />
</cffunction>
In my next post we will look at the code to validate the user at log in.



Just wanted to thank you for doing this series. Security is nothing to take lightly, and this has opened my eyes on some of the ways I have been doing it.
Thanks again,
Chris
Still loving the series and this is another great post. Just a quick "Devil's Advocate" question:
I feel a little uncomfortable about purposely slowing down my code just to thwart hackers from brute force attack. Would a suitable alternative to this be something like preventing the user (by session redirect) from logging on after X amount of failed attempts?
Keep up the great work mate!
Pete
I am going to be inserting data into a mySQL database of a field that I intend to encrypt using the encrypt function in CF using the cfx mode with a very safe key and the field is salted with another secure string before the encryption happens.
Now my question, which would be the best encryption method to use: uu, 64bit or binary?
So for our processing it really does not add that much time.
As for your question, the idea is not that we are purposely slowing down our application to avoid the brute force attack. We are purposely slowing down the hacker. As I said, the hacker's attempts will take 1000 times longer, but our preventative code will only take 15-16ms. Keep in mind that all we are doing is overwriting a variable over and over. The hacker, who is doing a brute force attack will have to go through the process of retrieving the password, hashing it, sending a login request, have it fail, hash the password again, send it again, have it fail, etc until he has done that the correct number of time with the correct password. So it will REALLY slow him down.
As for the second part of your question, yes, having some sort of mechanism that monitors login attempts and locks out users that have made too many attempts, whether by session or by IP, is a good idea. But session cookies can be deleted, and IPs can be spoofed. There are plenty of automated tools out there to get passed our attempts to slow them down via clever programming.
Something I always try to remember is: "Hackers are smarter than I am"
UU, 64Bit and Binary are not Encryption Methods, they are encoding options for representing encrypted data (which is Binary) as a string for storing in a database. Kind of like if you ToBase64() an image. And I am pretty sure that which one you choose is a matter of preference.
The encryption algorithm is what you want to be concerned with when it comes to the level of Encryption. And for that, with the Encrypt() function in ColdFusion, you have the choice of AES, Blowfish, DES and DESEDE.
I have not done a ton of research on this yet, so I cannot make a firm recommendation on which one to use. I will hopefully get to my Encryption posts (and research) later this summer.
I can tell you that the last time I looked into it, Blowfish, AES, and DESEDE(TripleDES) all seemed like the excellent solutions. But DES should be avoided.
Reference: http://kb.adobe.com/selfservice/viewContent.do?ext...
illustrates the invoke method? Any assistance you could lend would be much appreciated.
By the way, thanks for the great information!
Go to the DOWNLOAD link at the bottom of this blog post (right above where the comments start).
You are the greatest -- all I needed was something to go by for syntax since my old Ben Forta book is for CF 5! Guess it's time for another book!
Thank you again and I am glad I found your page. Now I'm going to take my new toys and go to work!
Awesome work on your salting and hashing posts. I've read a hand full of them now and have been super impressed at the quality and deatil you've expressed.
One thought that crossed my mind to slow down brute force attackers without delaying your regular users (even if it is only taking milliseconds) would be to create a incorrectLoginCount and use it to exponentially delay the user's next login attempt. E.g on the first incorrect login attempt would not delay them at all, the next few would receive minor (but unnoticable) delays and as the incorrectLoginCount grew so too would the delay between each successive attempt. Obviously resetting the counter upon Session expire or successful login attempt if the counter were being persisted to the database.
Not sure on the exact logistics of implementing this, but in my head - it seems like a cool idea!
Thanks for the comment and kind words. I am always glad to hear that someone is getting value out of my works.
As for your suggestion of altering the login time for each successive login attempt to slow down hackers. While I agree something must be done to slow them down, i think there are less complicated way to do it. Check out the comments thread in this post.
http://www.12robots.com/index.cfm?mode=entry&e...
Don't take my word for it though. Try implementing your idea in a sample app and see where it takes you. Maybe you'll discover something cool, but it's certain, you will learn something.