Basic Web Application Security - Enforcing SSL

Many web applications deal with data considered to be confidential or sensitive in nature. Applications like this should use SSL to encrypt the traffic between the server and the user (you are using SSL...right?). Most web servers, however, are not configured to only accept a secure connection.

The programmatic method for redirecting an insecure request over http to one using https relies on checking the https variable in the CGI scope. If it is not set to on, then we know that a redirect is needed to enforce https.

The following code uses the tag to send a 301 HTTP status code, which tells the browser that the requested page is permanently relocated, followed by a Location header to refer the client to the correct URL, which uses https. The reset is used to throw away any content already generated to this point in the code so that it is not sent back to the client.

<cfif cgi.https IS NOT "on">
<cfcontent reset="true">
<cfheader statuscode="301" statustext="Use SSL">
<cfheader name="Location" value="https://#cgi.http_host#">
<cfabort>
</cfif>

The above example relies on the application to perform the SSL check. If you have control over your web server, you may be able to move the check up a level by using URL rewriting or a web server-specific setting.

Basic Web Application Security - SQL Injection

Web application security is growing to be an interest of mine, especially after going through a round of audits against the application that pays my salary. With those audits (almost) behind me, my intent is to write a series of articles detailing some of the common vulnerabilities found in web applications and how they can be resolved in ColdFusion.

First up, SQL injection.

[More]

Datasource-less Queries in ColdFusion Using JDBC

Is it possible to execute a query in ColdFusion without defining a datasource in ColdFusion administrator? Yes! The following is one method, I'm sure there are others, for executing a ColdFusion query without explicitly defining a ColdFusion datasource.

What We'll Need

  • ColdFusion Engine
  • Database Driver JAR

I will assume you already have a ColdFusion engine installed and running. I tested this code on Adobe CF 9.

For this example, I used the MySQL Connector/J driver to connect to a local MySQL database. Place the JAR file in your ColdFusion classpath.

Steps

Before we begin, a note of caution. Java is case sensitive, so when instantiating an object using a Java class, case matters!

Create a Datasource

The first step to creating a manual connection to the database is to create a datasource using the com.mysql.jdbc.jdbc2.optional.MysqlDataSource class, which is part of the MySQL Connector/J library.

<cfset datasource = createObject( "java", "com.mysql.jdbc.jdbc2.optional.MysqlDataSource" )>

Create a Connection

Using the datasource, create a connection object, passing in the identity of user to connect as. The datasource class has a method, getConnection(), that makes creating a connection simple. Use the setter methods on the datasource to provide the login details for the user credentials and the name and port of the server to connect to.

Please, please, please do not use root! Create and use a user account with only the permissions it needs.

<cfset datasource.setUser( "cfuser" )>
<cfset datasource.setPassword( "12345" )>
<cfset datasource.setServerName( "localhost" )>
<cfset datasource.setPortNumber( 3306 )>

<cfset connection = datasource.getConnection()>

Execute the Query

Now that we have a connection to the database, we can use JDBC to execute queries. First, we'll need to create a JDBC statement, which is a class that defines the query to execute. The connection object has a method that once again makes it easy:

<cfset statement = connection.createStatement()>

With the statement object in hand, we can now write out the query to execute. The executeQuery() method on the statement class takes a string with the query definition. This method returns a JDBC resultset object.

<cfset resultset = statement.executeQuery( "SELECT table_name FROM information_schema.tables ORDER BY table_name" )>

Convert to a ColdFusion Query

At this point, the query is represented in a JDBC resultset. Although we could use this object, a ColdFusion query object is much more useful and feature-rich. Converting the resultset to a query object requires using one of the internal classes in ColdFusion, coldfusion.sql.QueryTable, passing the resultset into the constructor:

<cfset query = createObject( "java", "coldfusion.sql.QueryTable" ).init( resultset )>

Clean Up

The JDBC connection needs to be cleaned up when it is opened. Keeping it open may result in oddness and other memory-related issues.

<cfset connection.close()>

Out of the Comfort Zone - A First Introduction to CFWheels

I've decided to step outside my comfort zone and try out a new framework, CFWheels. CFWheels describes itself as "an open source CFML framework inspired by Ruby on Rails." It advocates conventions over configuration, which seems to be the latest craze to hit CF frameworks (see ColdBox and FW/1 for two others).

Since I'm going outside my comfort zone, I think CFWheels is a good framework to explore since it supports several unfamiliar and/or uncomfortable areas for me:

  • Convention over configuration - I am a long time Fusebox user
  • ORM - I proudly admit to being a control freak when it comes to the data layer
  • URL rewriting - More than just pretty URLs?

Creating a New CFWheels Site

According to the documentation, setting up a new CFWheels application is rather straightforward. Download CFWheels, extract the zip file to the web root, and voila, a new CFWheels site.

For my first site, it was indeed this easy. I created a directory, extracted the CFWheels files into it, and I was done (almost...).

The Default Route

I wanted the site to be under a directory named "reading" After creating such a directory and adding in the CFWheels skeleton, however, I immediately hit an error message. Not a ColdFusion-generated error, but a rather friendly CFWheels error message indicating that a view could not be found:

After poking around the documentation and code a bit, I realized that the default route for a fresh skeleton application was set to look for a file named wheels.cfm under views/wheels. The config/routes.cfm template has the following lines of code to set up the default action:

<!---
    Here you can add routes to your application and edit the default one.
    The default route is the one that will be called on your application's "home" page.
--->

<cfset addRoute(name="home", pattern="", controller="wheels", action="wheels")>

Translated, the addRoute() line tells CFWheels to look for a controller CFC named wheels in the controllers directory and a CFM template named wheels.cfm under a subdirectory named wheels in the views directory. (This conventions thing is rather handy.)

The error message I received pointed to a problem I introduced while setting up the site. I renamed the default "wheels" views directory to "reading," not realizing that I was breaking the default route.

The fix was simple, either restore the views/reading directory to views/wheels, or, and this is the option I chose, change the route to to point to the existing views/reading directory:

<cfset addRoute(name="home", pattern="", controller="reading", action="wheels")>

Next Steps

So now that I have a happy CFWheels skeleton site, what next? The site I had in mind is a simple application to track what books I have read, so I need to take a step back and design the model and the screens, pardon me, views, that need to exist.

Once the basic design is set, I want to explore CRUD automation using CFWheel's ORM. I need to see if I can just let go and allow a framework to automate a good portion of the data layer.

OT: Windows 7 Maybe?

I use a Mac for my personal work and a Windows XP machine for gaming and a few PC-only apps. I never thought twice about upgrading Windows to Vista, but I am certainly thinking about going to Windows 7.

So what brought about the change of heart? I set up a new computer for my mom last night, a HP slimline...wow, is it shiny and kind of cute, which came with Windows 7 Home Premium on it. My first experience actually driving Windows 7, and I came away really liking the changes and polish added to the OS.

The graphics are nice and shiny, looks like they took a page from Apple's design book, the speed is there, and the features and improvements really look like someone cared about this release of Windows. The improvements in searching alone are a big plus in the pro column on the go-and-get-a-copy list.

Many of the features I like about OS X, the speed, the graphics, Finder and Spotlight, are pretty much all there on Windows 7. Just one question: will it run Civilization IV? ;-)

Just maybe a trip to Micro Center is in order this weekend...

CF Code-Fu Atrophy

It was bound to happen.

I no longer get to code as often as I would like, so when I got the opportunity to make a quick fix to help bring my company's software up to CF 9 snuff, a problem with nested WDDX packets, I decided to keep the task to myself. A short time later I had the solution, wrote the necessary code, checked it in the browser, and then committed the file to source control feeling the old coding euphoria set in.

This morning, however, one of our developers called over the cubicle wall saying something was not right. Yep, I made a syntax error. My sense of accomplishment withered into feeling like a newbie. I made a mistake, one that I often coach others on: I did not sufficiently unit test my code change.

Once I got over the blast to my coding ego, I made the (small) code fix, unit tested again, and committed the file to the repository.

My lesson learned is two-fold:

First, never overestimate your own coding ability. There is always room for improving and refreshing both your language knowledge and your development practices.

Second, find time out from designing software to actually write some code. Do not let your code-fu wither due to disuse.

Using a ColdFusion Datasource in Java

From time to time I have to switch out of ColdFusion into Java to get a task accomplished. The latest was writing a password callback class for a web service integration project using ColdFusion, aka the Axis web service engine, and WSS4J.

[More]

Creating a Self-Signed Key Pair

One of my recent projects was to design a web service-based API for an existing Fusebox 3 application (more on that later). The data exchange has to be digitally signed, which requires working with public and private keys within ColdFusion.

ColdFusion uses the Java keystore within the JRE to handle keys and matters of trust. A keystore is simply a storage location for keys and certificates. Most keystores are physical files protected with a password. By the way, the default password for the ColdFusion keystore is "changeit."

During the prototyping and development phases, I determined that using a self-signed key was faster and easier than having to go through the process of obtaining a "real" signed key.

Note: Self-signed keys are useful for development, but a real key should be used in production environments.

General Syntax

The general syntax for generating a self-signed key pair using the Java keytool utility is:

keytool
-genkey
-alias <alias of key>
-keypass <password for alias>
-keystore <path/to/keystore>
-storepass <keystore password>
-dname "cn=<alias>"
-keyalg RSA

My project required using the RSA key algorithm. If you do not specify the algorithm to use, the keytool utility uses DSA.

Using the Keytool Utility

Using the keytool utility requires going to the command line, so GUI-lovers beware! I'm going to use the Windows command line in my examples below.

The keytool utility lives in the bin directory of the Java runtime associated with ColdFusion. The default keystore for ColdFusion, named cacerts is in the lib/security directory, so any references to it must be the full path.

cd c:\coldfusion9\runtime\jre\bin

To list the current contents of the ColdFusion keystore, use the -list switch:

keytool -list -keystore c:\coldfusion9\runtime\jre\lib\security\cacerts -storepass changeit

Generating a key pair uses the -genkey switch. In this example, I create a RSA key named mykey stored in the cacerts keystore, and then self-sign it:

keytool -genkey -alias mykey -keypass secureme -keystore c:\coldfusion9\runtime\jre\lib\security\cacerts -storepass changeit -dname "cn=mykey" -keyalg RSA

keytool -selfcert -alias mykey -keypass secureme -keystore c:\coldfusion9\runtime\jre\lib\security\cacerts -storepass changeit

To share the public key with another application, you will need to export the certificate from the keystore using the -export switch:

keytool -export -alias mykey -keypass secureme -keystore c:\coldfusion9\runtime\jre\lib\security\cacerts -storepass changeit -file export\file\path\mykey.cer

Importing a key also uses the keytool utility, this time with the -import switch:

keytool -import -alias the.key.alias -file path\to\certificate.cer -keystore c:\coldfusion9\runtime\jre\lib\security\cacerts -storepass changeit

Note: Once a key exists in the ColdFusion keystore be sure to restart the ColdFusion Application Server.

The Persistant SQL UDF

I came across a very strange and unexpected problem with a SQL Server 2005 UDF yesterday that continues to puzzle me. First, the cast of players:

  • ColdFusion MX 7
  • SQL Server 2005
  • A table-valued function
  • Puzzled developers

In case you are not familiar with table-valued functions, they are functions in SQL that return a table, as opposed to the more traditional scalar value.

We had to change the data type for one of the columns in the returned table from decimal to text to fix a bug. Nothing a simple ALTER FUNCTION statement could not handle.

Script, run, test, same error, what?

Maybe something is cached on the SQL Server side. Let's try dropping and recreating the function.

Script, run, test, same error, ???

Something very odd was happening. Only after restarting the ColdFusion Application Server service did the error go away.

I am still searching for an answer. Surely ColdFusion does not cache database object information...?

CFUnited the Fourth

CFUnited is this week, and I will be there from Wednesday to Friday. Since this will be my fourth CFUnited - I have the t-shirts to prove it - I have a pretty good idea of what the sessions and format will be like. The three days will be packed with information that is nearly impossible to remember without rereading any notes I happen to take.

CFUnited sessions are far to short to fully cover most topics. ColdFusion is just too deep and rich to do so. Instead, I approach each session with the following goals:

  • Learn one new aspect of the topic. For example, what does an XSS attack look like in the logs.
  • Get introduced to the broad aspects of the topic. For example, what are the high-level abilities of ColdFusion to connect to a Microsoft Exchange server.
  • Get acquainted with the latest buzzwords and "must-haves" in the ColdFusion world. A little tongue-in-cheek, but unfortunately I do not always have time to keep up with the various email lists and blogs.

Each session is an opportunity to become interested in a new or different approach to solving a problem (and everything is a problem to resolve). Just leave room for chatting with vendors and maybe even other developers. ;-)

More Entries