"Look, Ma. No Password!" - Secure Hashing in ColdFusion

Wednesday, June 24, 2009

I soaked up tons of great stuff at Frank Kim's recent Sansfire 2009 training in Baltimore. As a matter of fact, it was the single best training event I have ever attended and I highly recommend it. After the module on Java Cryptography Architecture (JCA) -- which was at the end of Day 3 and though my brain was fried -- I realized I had a big gap in my own knowledge in something that should be a fundamental skill for programmers today. Broadly and simply stated, that skill is to be able to protect data in your application. Now, if you're anything like me and you start hearing some terms like symmetric and asymmetric ciphers, MD5, SHA-1/2/3 message digest, cryptographically secure random number generation, etc., you might be inclined back away slowly (or quickly) and leave all that to someone else. Well, I'm here to say that implementing strong cryptography in ColdFusion is a lot easier than I expected. And knowing how do this and why will give you valuable skills that can only make your software safer and your programming stronger.

Let's start with a common web application task - storing credentials in a database. One appealing NIST recommendation is that you should not store the passwords at all. Rather, you should store a secure hash of the password instead. When authentication needs to take place, instead of reading the password from a database and comparing that to the password entered by the user, you retrieve the password hash from the database, hash the password entered in the form, then compare the hashes. If you understand why we do this and just want to see how, skip down to Secure Hashing. If you're mumbling to yourself "That sounds like a fucking waste of time," read the next two paragraphs. The driver here is that passwords are secret and nobody should have access to a user's password other than the user. System administrators and support staff should have the ability to reset passwords but not to read them. You might ask, "But my sites don't contain any sensitive information, why should I care?". Though true, how much do you want to bet that users registered on your site are using the same set of credentials to log into other sites, even banks? Does this possibly make your site a target for harvesting? Could this challenge customers' trust in you over time? Play that tape couple of times ...

The good news is that password hashing is so simple I can see no real reason not to do it. I'm not claiming to make your site secure; I'm simply saying that if you securely store password hashes instead of passwords, you can mitigate a number of potential attacks; for example, the Rainbow Table attack [7]. Note that password hashing differs from storing passwords encrypted. Why is this important? Because anything encrypted needs to be unencrypted to be read. To unencrypt, there must be a key and frequently it will be one key that can be used to read all passwords. We don't ever want passwords to be read by anyone. Period. So, we want to create a strong, secure, one-way hash. Secure Hashing The technical term is Cryptographic Hash Function, and there are several algorithmic variations : most notably, Message Digest (MD5), Secure Hash Algorithm (SHA), and others. Essentially, a hash function generates a unique and fixed-sized representation of some data; aka a Fingerprint. A correct hash will always produce the same result for a given input; e.g., f(x)=y. For example, the string foo, when hashed with MD5 should always produce ACBD18DB4CC2F85CEDEF654FCCC4A4D8 in ColdFusion. If another algorithm is used, the output will be different than this, yet it still should always produce consistent output.

Now, what if there are users with the same passwords? Won't the hashes be the same in the database? Right you are. What a Rainbow Table[7] is, is essentially a large list of passwords that have been hashed using a number of algorithms. The attacker compares the hashes in your database with the ones in his Rainbow Table and then finds the matching password. The solution to this is to create unique hashes using salt and to repeatedly hash the hash. Salting is the process of inserting random data into the original data. Then, we repeat the hashing about 1000 times. This creates a unique and, if done correctly, a more secure hash. Let's start with some usage. We use an example utility component ,Crypto , to perform the hashing. Full source code can be found here.

 <cfset user_id = "bill" />
 <cfset password = "p@ssW0rd" />
 <cfset crypto = createObject('component', 'Crypto') />
 <cfset salt = crypto.genSalt() />
 <cfset passwordHash = crypto.computeHash(password,salt) />
view raw This Gist brought to you by GitHub.

When run, this generates a password hash that looks something like 72C2CA24AD19EF7A8A9FC89184BA17BFA2D65CF3BE4FD2F0BBF3B460BD123550BC2D6BAB3AADF76EEAA4D8B5F6641A73365B21D17158779468049CACC32F0F2E and a base64 secure random salt value of 4OP5GFmp/z0YYgUUlprVoig4pkGWhNGgMl37Tn4sLPw=. When a user creates or changes their password, store only the hash and salt:

 <cfquery name="q" datasource="users">
    insert into users
    (user_id,password_hash,salt)
    values
    ('#user_id#','#passwordHash#','#salt#')
 </cfquery>
view raw This Gist brought to you by GitHub.

Now, to authenticate a user, you do something like this:

 <!-------------------------------------------------------------------------
Assume a login form with username and pasword:
form.user_id and form.password
-------------------------------------------------------------------------->
 
  <cfquery name="loginQuery" datasource="users" maxrows="1">
    SELECT password_hash, salt
    FROM USERS where user_id = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#form.user_id#" maxlength="12" />
  </cfquery>
 
  <cfset hashedFormPassword = crypto.computeHash(form.password, loginQuery.salt) />
 
  <cfif loginQuery.password_hash eq hashedFormPassword>
   Valid user.
  <cfelse>
    Invalid user.
  </cfif>
view raw This Gist brought to you by GitHub.
We're simply comparing the hashed value of the password entered by the user to the hashed value stored in the database. We do this by first retrieving the salt from the database and using that to generate the hashedFormPassword value. If you've read this far, I'm sure you want to look under the hood:
<cffunction name="computeHash" access="public" returntype="String">
  <cfargument name="password" type="string" />
  <cfargument name="salt" type="string" />
  <cfargument name="iterations" type="numeric" required="false" default="1024" />
  <cfargument name="algorithm" type="string" required="false" default="SHA512" />
  <cfscript>
    var hashed = '';
    var i = 1;
    hashed = hash( password & salt, arguments.algorithm, 'UTF-8' );
    for (i = 1; i <= iterations; i++) {
      hashed = hash( hashed & salt, arguments.algorithm, 'UTF-8' );
    }
    return hashed;
  </cfscript>
</cffunction>
view raw This Gist brought to you by GitHub.

It doesn't get much easier for a complex topic, does it? computeHash() accepts 4 arguments: password, salt, iterations, and algorithm. The required ones are password and salt - salt should be a secure random base64 string. iterations is the number of times the hash will be rehashed. PKCS 5 recommends doing this "a modest" 1000 times[9]. This would be a performance concern if this operation were done frequently, but since it is done only when a user logs in or creates an account, it's considered acceptable. The last parameter, algorithm, is a specific message digest algorithm. It's specified here are SHA512, which is the strongest FIPS-140 approved secure hashing algorithm.

Adobe has some very good documentation on available security providers and other related security best practices - this is required reading for ColdFusion developers! [5] Salt Generation: The core concept behind salt generation is to create a random set of bytes of N length. Since ColdFusion sits on Java, I chose the java.security.SecureRandom class.

<cffunction name="genSalt" access="public" returnType="string">
    <cfargument name="size" type="numeric" required="false" default="16" />
    <cfscript>
     var byteType = createObject('java', 'java.lang.Byte').TYPE;
     var bytes = createObject('java','java.lang.reflect.Array').newInstance( byteType , size);
     var rand = createObject('java', 'java.security.SecureRandom').nextBytes(bytes);
     return toBase64(bytes);
    </cfscript>
</cffunction>
view raw This Gist brought to you by GitHub.

Summary Using the example Crypto component or your own variation will give you a viable option to storing passwords directly in the database and contribute to better security in your application. However, do not take my word alone for this. Please do some thorough research and learn for yourself. When it comes to protecting your customer's data and privacy (and your job) make sure you know what you are doing and why.

Test and be Happy!

References (Many are PDFs):
[1] OWASP Java Hashing - http://www.owasp.org/index.php/Hashing_Java
[2] NIST Secure Hash Standard - http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
[3] FIPS-140-2 Draft (June,18,2009) - http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf

[4] Guide to Enterprise Password Management (Draft) - http://csrc.nist.gov/publications/drafts/800-118/draft-sp800-118.pdf
[5] ColdFusion 8 developer security guidelines - http://www.adobe.com/devnet/coldfusion/articles/dev_security/coldfusion_security_cf8.pdf
[6] Java Cryptography Architecture (JCA) - http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html
[7] Rainbow table - http://en.wikipedia.org/wiki/Rainbow_table
[8] NIST Advanced Encryption Standard Algorithm Validation List - http://csrc.nist.gov/groups/STM/cavp/documents/aes/aesval.html [9] PKCS #5 v2.1: Password-Based Cryptography Standard - ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2_1.pdf

IntelliJ IDEA Plugin for CFML

Saturday, June 13, 2009

As ColdFusion developers, unlike many other languages, the one thing we simply don't have is code insight or object & method resolution for 3rd party Java or ColdFusion products. I understand that this is difficult to achieve for dynamic languages, but, just because it's "hard" is not an excuse, imo. I'm a big fan of IntelliJ IDEA and it's the best tool for Java and Groovy development I've used - these guys know what an IDE should do and they also support open source projects. IDEA also gives you the ability to create Flex and Air projects. Recently, developer Valeria Nikolaenko, has built a CFML plugin for IDEA and has consistently been releasing updates. The most recent one fits especially nicely with any project that uses ColdFusion and Java together. Specifically, if you use Mark Mandel's JavaLoader you'll find this feature of particular interest. Basically, it allows you to get Java method resolution inside of CFML for classes loaded with JavaLoader. Check it out:
So, what we've done here is create a JavaLoader instance using createObject(...) and then we create a Java class, esapi, in the editor. When you type esapi. then hit Ctrl+Space, Voila!, all the methods and their signatures for the ESAPI class are presented in the editor. You do have to perform a few project set up tasks in order to make this happen in IDEA, assuming you've installed the CFML plugin already:
  1. Add your 3rd party jars to your project's class path
  2. Add the ColdFusion facet to your project and tell it where your webroot and subdirectory are located
  3. In your source code, tell the CFML plugin about your JavaLoader variable and jar locations: <!---@javaloader name="loader" jarPath="/home/webapps/cfesapi/lib/" --->
If you've ever done Java development without code insight, you know what the typical process is - you need to constantly go back and forth between the Javadoc APIs, copy and paste, or you dump out the object's metadata and try to figure out how to call it. The configuration above steps seem like minimal effort compared to the typical manual process required to work with Java inside of ColdFusion. It's not the end-all-be-all solution, but it's big step in the right direction. Ideally, if all the configuration could be done at the project level, that would even be better. Now, if we could just have an MXUnit plugin for IDEA, it could be a seriously dangerous all-around IDE for $249 US.

Continuous Integration with Hudson, CF, and MXUnit: Setting up Notifications

Thursday, June 4, 2009

In previous entries, I wrote about configuring a project in Hudson and setting up your project to run your MXUnit tests and report results. Before we talk about setting up email and IM communication, let’s briefly look at what you should now have, in pictures, if you’ve set up a project. I’m using MXUnit as the example project here.

First, an entry in the project list, indicating the build’s health

hudson_mxunitbuildhealth

Next, when you drill into the project, you’ll see your recent build results on the left, along with your test trends on the right

mxunit_projectstatus

On the left side, with your list of previous builds, you can click the “trends” link and see a time trend graph

hudson_timetrend

You can click on a link for your last build and see more details about it. When you click on the Test Results link, you get this view

mxunit_passedbuild

From there, you can drill down into the reports for more information, should you need it

If a build fails, it’ll show you something like this:

hudsonbuildfailure

Communicating This Information

All of this information is lovely; however, we’re not interested in monitoring the Hudson interface every time a build runs. Instead, we want to get notified when things change. That’s it: when build status changes. For me, continuous integration is as much about communicating results as it is about providing an easy, scheduled mechanism for running your tests (we don’t care about compiling and linking in CF applications, so that core benefit of CI doesn’t apply to us either).

Ideally, only interested parties would be notified on a change in build status. For example, let’s say a build runs at 8:00 AM, and all tests pass. It runs again at 8:15 AM, and tests fail. What I want to happen is:

  1. Hudson looks at source control for the users who have committed code since the last build
  2. Hudson notifies *just* those people that the build is now failing.
  3. Hudson does this either via email, instant message (SMS), or both.

Fortunately, this is all possible. Let’s set it up.

Configuring Email Settings

From the main Hudson screen, type “configure” in the search box

Scroll down to the bottom and find the E-mail notification section.

I’m using gmail in this case, so I plugged in my gmail credentials, using “smtp.gmail.com” as the server. I’m keeping “default email suffix” blank since this can’t be computed (this would be more for corporate email accounts where you can trust that the email would end up as “firstname” + “lastname” + default email suffix, for example).

In the Advanced settings, I checked “use smtp authentication”, entered my email address into the username field, added my password, checked “use ssl”, and specified the port as 465

 

Configuring SMS (Jabber) via GTalk

From the “manage Hudson” screen, click on Manage Plugins

go to “Available Plugins”, and find the “Hudson Jabber notifier plugin”. Click things and install it. Restart if necessary.

Now, back in your Manage Hudson screen, you’ll have a new section, right above the Email section, for Jabber.

I entered my gmail address and password, and “talk.google.com” as the server. That’s it!

For the visually inclined, here’s what all of this looks like:

hudsonnotificationsetup

Noise Control

At the project level, you can also configure how noisy you want this communication to be. Here’s what that looks like:

hudson_notificationconfig

From that image, you’ll see that I can configure when I want to be notified… every build, just on change, etc. Thus, to substantially reduce the noise from your scheduled builds, go into the project and configure it to only notify via IM on status change. This, in my humble opinion, is gold.

Configuring Users

Now that the communication mechanisms are set up, we have to associate email addresses with the subversion users. Quite possibly there’s an easier way to do this via some batch process, but as I’m just getting started with my Hudson investigation, I haven’t looked into it. So please don’t take this as “the only way” or “best practice”, because I do not know that to be true.

For my setup for MXUnit, I linked it to SVN and when it updated and there were changes, it created new a new user for any user that was associated with a change. So, I committed some code to MXUnit, ran a Hudson build, and Hudson added me as a user, silently.

To give the “marc.esher” user notification details:

  1. from the main Hudson screen I clicked on “people” then on “marc.esher”. (You can also get here if you know the username you want to configure by typing that username in the "Search” box at the top of the screen)
  2. click Configure
  3. enter my email address
  4. since I installed the Jabber plugin, it also has a space for jabber credentials. I entered my gmail address again.

So what’s all this get me?

After this configuration was finished, here’s what I get:

Emails on build failure that look like this:

hudsonbuildfailure_email

GTalk notifications on build failure that look like this:

hudsonbuildfailure_gtalk

And corresponding messages for when things go back to normal.

Importantly, what I don’t get: noise. I don’t get notified on every build via email. I don’t have to constantly go to a website to check the build status. I get notifications when I care about them: when things go bad, and when things go from bad back to good.

Summary

Continuous Integration is about communication. It’s about noise control. And so far I’m discovering that Hudson is performing admirably. You can configure different methods of communication, all hooked into source control, with different “strategies” (on every build, on every change, etc). I appreciate this level of configurability. In addition, I was able to get all of this going without reading a single page of documentation. I think that speaks to Hudson’s ease of use.