April 7, 2020
Best Practices for Secure Password Storage in ColdFusion
Comments
(0)
April 7, 2020
Best Practices for Secure Password Storage in ColdFusion
Master 31 posts
Followers: 17 people
(0)

In today’s post, I want to discuss best practices for storing passwords securely.  The examples I will provide are directed towards ColdFusion development. However, this is not limited to ColdFusion; these principles apply to any software development project.

The first best practice of secure password storage is:

Never, ever, ever, ever, ever, ever store passwords in the clear.

The biggest mistake that a developer can make is to store passwords in the clear.  I have seen countless ColdFusion websites connected to a database that contain some iteration of the following table:

userID username password
1 admin admin
2 info admin
3 webmaster w3bM@$t3r

If someone with nefarious intention were to obtain access to this table, all of the usernames and passwords would be compromised.  Someone could log in and perform actions as any user in your application, causing a massive security loophole.

Why do developers store passwords in the clear?  In discussion with developers and administrators, I’ve been told that they feel the need to know what specific user passwords are, or require a means to be able to look up a user’s password if necessary.  This brings us to the next best practice tip:

Let go of the idea of being able to access a user’s password.

As a best practice for secure password storage, you need to let go of the notion of being able to look up a user’s password.  If you’re concerned about the security of your application (and you should be) then you must build in reasonable security measures to protect your data.  Consider these rules from a security standpoint:

  • No user should be able to see any user’s password, including their own.
  • A user should be able to change their own password.
  • An administrator should be able to assign a randomly generated password to a user, but that password should be changed to a user assigned password on first login.

The bottom line is that you no not need to know, or even be able to look up what a specific user’s password is.  Let it go.

Once that notion has been purged from your expectations, you may be asking yourself, “Self… how do I store passwords without storing the password?”  It’s simple:

Hash your passwords

ColdFusion, like most programming languages has a built in hash() function that will perform a one-way encoding of a string into a fixed-length string.  ColdFusion’s hash function takes four arguments:

  • string – the string you want to hash
  • algorithm – the algorithm used to hash the data
  • encoding – the character set encoding used to create the result of the hash, defaulting to the “defaultCharset” attribute of ColdFusion’s neo.xml file, but is typically “utf-8”.
  • iterations – the number of times ColdFusion will iterate over the hash making it more complex, but also more computationally intensive.  This value defaults to 1.

Let’s create a new field in that users table above called “passwordHash” making it a char variable type with a length of 40 characters and run the following ColdFusion script:

<cfquery name=”getUsers”>
  SELECT * FROM Users
</cfquery>
<cfloop query=”getUsers>
  <cfquery name=”setPasswordHash”>
    UPDATE Users
    SET passwordHash = <cfqueryparam cfsqltype="char" value="#hash(Password,’SHA’)#">
    WHERE (userID = <cfqueryparam cfsqltype="integer" value="#userID#">
  </cfquery>
</cfloop>

Looking at the resulting table, this is what we see:

userID username password passwordHash
1 admin admin 4ACFE3202A5FF5CF467898FC58AAB1D615029441
2 info admin 4ACFE3202A5FF5CF467898FC58AAB1D615029441
3 webmaster w3bM@$t3r 9001EC3B7E9293AF92D5F35014C580779AD5EDA2

This is better.  Now that we have a hash of the password stored, we can start authenticating users based on the password hash and not the password in the clear.  Once we do that, we can drop the password column, and clean up our exposed data. We’re well on our way to best practices for secure password storage!

But we’re not quite done yet.  There’s a problem here; the password hash for the admin and info user are exactly the same, since they used the same password.  The username/password combination may be distinct, but if one part of that equation matches another record in the table exactly, it’s not as safe as we can make it.  The next step is to:

Add some salt

In order to create unique password hashes for each user, we are going to perform a technique called “salting the data.”  A password salt is an additional hash, randomly generated, that gets appended to the password in order to guarantee uniqueness.  The first thing I am going to do is make some changes to the users table. I will:

  • Modify the passwordHash column to be 128 characters in length.
  • Add another column called passwordSalt, that is also a char field, 128 characters in length.

The reason for updating these fields is to accommodate the change I am making to the hashing to support the much stronger SHA-512 algorithm in my ColdFusion script.

Looking at my script above, I’ll make some modifications and run the following:

<cfquery name=”getUsers”>
  SELECT * FROM Users
</cfquery>

<cfloop query=”getUsers>
  <cfset passwordSalt = hash(generateSecretKey(“AES”),”SHA-512”)>

  <cfquery name=”setHashedPassword”>
    UPDATE Users
    SET
      passwordHash = <cfqueryparam cfsqltype=”char” value=”#hash(Password & passwordSalt,’SHA-512’)#”>,
      passwordSalt = <cfqueryparam cfsqltype=”char” value=”#passwordSalt#”>
    WHERE userID = <cfqueryparam cfsqltype=”integer” value=”#userID#”>
  </cfquery>
</cfloop>

Running this script, and looking at the table, we can now see very strong, secure password storage.

userID username password passwordHash passwordSalt
1 admin admin 03C3529A170… 13C55682B9…
2 info admin 323FC900F49… 7559EBC821…
3 webmaster w3bM@$t3r 5F90E940583… 9E29A211D39…

Now that we’ve stored the hash of the salted password, and the salt itself, your authentication will require some modification.  You need to get the password hash and salt of the user you are trying to authenticate against and perform the comparison in ColdFusion.

<cfquery name=”Authenticate”>
  SELECT
    passwordHash,
    passwordSalt
  FROM
    Users
  WHERE
    Username = <cfqueryparam cfsqltype=”varchar” value=”#form.username#”>
</cfquery>

<cfif !Authenticate.recordCount>
  <!--- The user is not in the database.  Redirect them to the login page with an error message. --->
</cfif>

<cfif Authenticate.passwordHash eq hash(form.Password & Authenticate.passwordSalt, SHA-512”)>
  <!--- User is authenticated. Run whatever code is needed to establish a user session. --->
<cfelse>
  <!--- User is not authenticated. Redirect them to the login page with an error message. --->
</cfif>

Excellent!  We’re no longer authenticating against passwords in the clear.  We are salting password hashes before we store them in the database.  We’re comparing the hash of the salted password to the user entry. The security of our application is looking much better! But there’s one final step…

Remove Insecure Data

The very last step is to drop the column of passwords in the clear from your table.  Once this is done, and users are being authenticated against a password hash and password salt, you will be performing best practices for secure password storage in your ColdFusion application!

Happy coding!

0 Comments
Add Comment