18 April 2012
Note: Though this article talks about features in ColdFusion 8, it is applicable to the subsequent versions of ColdFusion, including ColdFusion 10.
One area you may not have heard much about are the helpful Ajax security features added in ColdFusion 8. Let's take a look at how ColdFusion can help secure your Ajax-based applications and what you can do as well.
The first feature look at is the verifyClient() function (see the documentation on this function). This is a pretty interesting function. It works in two places. For instance, you can use it as a simple function on a page, as follows:
Or you can use it as an attribute to the cffunction tag:
<cffunction name="discoverLastCylon" access="remote" verifyClient="true">
The function acts as a barrier to normal requests. As an example, create a new file named test1.cfm and paste in the following code:
<cfset verifyClient()> <cfoutput>The time is #now()#</cfoutput>
Running this code causes the error shown in Figure 1 to occur. What the function is doing is basically preventing any access outside of an Ajax-based access.
Now let's create a new file that demonstrates this behavior. Create a new file called pod1.cfm. This file creates a simple pod and points it back to the test1.cfm file created earlier. Place the following code inside pod1.cfm:
<cfpod source="test1.cfm" />
Next, I'll add a quick Application.cfc file. I'm not doing anything special in the file, so I won't show the code here (it's in the ZIP file), but I did enable session management. Now run pod1.cfm in your browser and you will see that test1.cfm loads just fine. If you go back to browsing test1.cfm directly, you continue to experience the error.
So what kind of voodoo is going on here? When ColdFusion creates the Ajax-based pod (or other controls) and then loads test1.cfm, it passes along particular information, including the use of session data, that bypasses the test1.cfm file.
You should use this function when you may have content that you intend to load only through Ajax. It's relatively simple to use tools like Firebug to see which HTTP requests are being made by your Ajax code and the attempts to open those URLs directly. The verifyClient() function can prevent that.
It's important to note that this protection isn't foolproof. It uses session-based variables and URL keys. If you use Firebug to monitor your ColdFusion requests, you can copy these URLs and load up the content yourself, but only after the first request has already been made. So while you shouldn't assume it completely block folks from requesting your content outside of an Ajax-based context, it will certainly go a long way to blocking most folks.
Let's look at one more example that uses a CFC method. The file, time.cfc, is a simple CFC that returns the current time:
<cfcomponent output="false"> <cffunction name="currenttime" access="remote" verifyClient="true" output="false"> <cfreturn now()> </cffunction> </cfcomponent>
This component has a simple method, currenttime, that returns the current time. The access attribute is set to remote to enable Ajax-based applications to retrieve the data, but note that verifyClient is set to true. If you run this method directly in your browser (using the name of the component and passing method=currenttime in the query string), you will get a similar error to the one you got above.
Now let's build a file to test this CFC via Ajax methods. The file, test2.cfm, uses the CFDIV tag bound to the CFC to display the results:
<cfdiv bind="cfc:time.currenttime()" />
When you run test2.cfm, you will see the time loaded inside the div. Again, ColdFusion performed all the security behind the scenes. The only real action on your part was adding the verifyClient attribute. One thing to keep in mind is that this change will prevent folks from using your CFC as a web service.
There are multiple places where you can enable this feature. The first is in the ColdFusion Administrator, which will make it a global setting. Under the Settings page in the Administrator, look for the "Prefixed serialized JSON with" option (see Figure 2). Selecting this option enables the feature, and the text box allows you to specify the prefix.
Your second option is to specify settings within the Application.cfc file. You can specify both the secureJSON option as well as the prefix using secureJSONPrefix. Here is a simple example:
<cfset this.secureJSON = "true"> <cfset this.secureJSONPrefix = "//">
The third option is related to the second, but works with the cfapplication tag. While most people should upgrade to using an Application.cfc file, if you are still using the older Application.cfm file, this is an option for you. Simply add the secureJSON and secureJSONPrefix attributes to the tag, as follows:
<cfapplication name="dharma" secureJSON="true" secureJSONPrefix="//">
Lastly, a fourth option is to supply the secureJSON attribute to a CFC function:
<cffunction name="getTime" access="remote" secureJSON="true">
With this option, however, you cannot specify the prefix. The prefix defaults to what is specified in the cfapplication tag value or the This scope. If neither of these is used, the prefix defaults to the value specified in the ColdFusion Administrator.
Once again, what's really nice here is that once you use this option, you can forget about it. All the code that ColdFusion generates on the client side automatically notices the prefix and updates itself for it.
There are a few additional items to keep in mind when considering Ajax security. First, during my exploration of ColdFusion 8 and the new Ajax features, I discovered what could be a minor security issue. ColdFusion 8 ships with a specific Ajax debugger. This debugger has to be enabled within the ColdFusion Administrator before it is used. However, unlike other debug settings, the Ajax-based debugger will ignore the attribute cfsetting showdebugoutput="false". To be safe, you should disable debugging on a production machine anyway, but it is something to keep in mind.
Second, "Ajax" does not equal "hidden." Tools like Firebug make it very easy to monitor Ajax requests. Therefore, any actions that you would secure within a non-Ajax context would obviously also need to be protected within an Ajax environment.