I was just reading on Terrence Ryan's blog about introspecting the Application.cfc data. The method he uses is so simple, so obvious that it blows my mind that I haven't seen this before. I don't want to jump on his coat tails, but when I saw this, I was so excited that I felt I had to share it. So, what is the goal here? Usually the question of application introspection comes up when someone whats to do something like:
- Check to see what the application name is.
- Check to see if session management is enabled.
- Check to see what the session timeout is.
The information sought out by these questions is defined in our Application.cfc ColdFusion component:
<cfcomponent output="false" hint="I define the application settings and event handlers."> <!--- Define the application settings. ---> <cfset this.name = hash( getCurrentTemplatePath() ) /> <cfset this.applicationTimeout = createTimeSpan( 0, 0, 20, 0 ) /> <cfset this.sessionManagement = true /> <cfset this.sessionTimeout = createTimeSpan( 0, 0, 5, 0 ) /> <cffunction name="onRequest" access="public" returntype="void" output="true" hint="I execute the requested template."> <!--- Define arguments. ---> <cfargument name="template" type="string" required="true" hint="I am the user-requested template." /> <!--- Include the requested template. ---> <cfinclude template="#arguments.template#" /> <!--- Return out. ---> <cfreturn /> </cffunction> </cfcomponent>
It's easy enough to see in the code, but when questions like this come up, how do we access this information programmatically? To start experimenting, we will often try to do something like access the Application scope:
<!--- Duump out the application scope. ---> <cfdump var="#application#" label="Application Scope" />
But, checking the Application scope is not very fruitful. When we run the above code, we get the following CFDump output:
As you can see, we only get the application name.
Next, we might look at the Application.cfc and realize that the OnRequest() event handler turns the user-requested template into a large mixin (see Application.cfc above). What this does is essentially execute the requested template in the context of the Application.cfc object, giving it access to all the Application.cfc scopes. In situations like this, you can access the THIS scope directly:
<!--- Because we are using the OnRequest() event handler, our target template becomes a mixin - essentially becoming PART OF the Application.cfc execution. As such, it lives in the context of the application instance and has access to Application.cfc scopes. ---> <cfdump var="#this#" label="Template As Mixin" />
When we run this code, we get the entire Application.cfc object:
This gives us all the information we need, but it only works in situations where the template we are executing is included directly into the OnRequest() event method. This excludes any custom tag execution or ColdFusion component calls (not to mention AMF style execution).
At this point, we might get kinky and examine the underlying Java objects available to us. After a lot of introspection of various scopes, we might find out that the Application scope itself has some very useful, undocumented methods like GetApplicationSettings():
<!--- Dump out application settings. This is a hacky way that leverages undocumented features of the language. ---> <cfdump var="#application.getApplicationSettings()#" label="Undocumented Application Settings" />
As you can see, here, we are accessing GetApplicationSettings(), an undocumented method on the Application scope. When we run this, we get the following CFDump output:
This gives us exactly the information that we need; but, in order to get at it, we need to use undocumented features of the ColdFusion language. This leaves a bad taste in our mouth and opens our applications up to future bugs. Furthermore, it gives us timeout values in Seconds, not franctions of a day (as defined by CreateTimeSpan()).
So far, we've explored three different attempts at introspecting our ColdFusion application information and none of them has been fully satisfactory. That is why I was so excited when I saw Terry's blog post. His idea can be used anywhere in the application with any type of request and does not use any voodoo magic. So, what did Terry suggest? Creating a new instance of the Application.cfc ColdFusion component:
<!--- Create a new instance of the application object. ---> <cfset applicationInstance = createObject( "component", "Application" ) /> <!--- Dump out the application instance. ---> <cfdump var="#applicationInstance#" label="Application Instance" />
As you can see, from within the current page request, we are creating a new instance of the Application.cfc. And, when we create this instance and dump it out, we get the following output:
Here, we get all the information that is defined in the Application.cfc. At first, you might be nervous that we'll accidentally invoke some of the event handlers; but, that won't happen. Remember, there is nothing special about the Application.cfc ColdFusion component other than the fact that the ColdFusion server looks for it when first executing a page request. Once you are in the middle of a page execution, however, attempts to create an Application.cfc instance will be treated the same as any other ordinary CFC invocation. Essentially, all that runs is the Application.cfc pseudo constructor. As such, you won't incur any boot-up costs associated with the OnApplicationStart() event method.
A huge thanks to Terry for pointing out such a simple but awesome tip!
How about a nifty way of resetting the application scope for any application on your server?
Anywhere on your server, create Application.cfc and index.cfm in the same directory.
Application.cfc should have the following two lines:
<cfset this.name= url.applicationName />
<cfset this.applicationTimeout = CreateTimespan(0,0,0,0) />
You can then call it like this
where anyApplicationName is the value of this.name for the application's application scope you want to clear
That's an interesting idea. I am not sure that this would work on a high-traffic site since applications don't time out immediately at their cut-off points (at least in my experience). Cool idea though.
Thanks for the heads up on high traffic sites. I haven't used it on production yet, mostly for refreshing things like bean factories (Lightwire, ColdSpring) on our qa/stage servers.
To turn the post on it's head...
How would you prevent someone from dumping the application vars using CF7?
Let's say I want to encrypt my application.cfc file and leave all the other CFM templates unencrypted. Within my encrypted application.cfc I would have a licensing function that check the license for my code.
OK I can stop them decrypting the template but if they just dumped #application# they may be able to reconstruct all the vars/session variables etc.
Is there a way to stop this?
While there are things that simply have to be available in the THIS scope, what you could do if you needed something hidden would be put in the VARIABLES scope of the Application.cfc and provide access to it via getter methods.
Of course, this is really only a minor fix as someone could always inject a tunnel into the Application.cfc to get all kinds of information about it. Heck, someone could even extend the Application.cfc object and view it that way (using CFDump and what not).
There's very little that is truly secure about actual ColdFusion files (from a server point of view). I've even worked with apps that had encrypted CFM pages that ended up including into other files with and working that way.
This is the problem I'm finding. I'm currently using a tool to encrypt the entire contents of my code admin folder which I encrypts and password protects the encrypted file so it's "impossible" to decrypt.
I wanted, however, to move away from this and just encrypt the application.cfc and hide the licensing module in there...
Will have to give this some more thought...
Actually I've figured it out :)
What I can do is encrypt the license sting stored in the application session var using an encryption salt that is known by both the application and the licensing server.
If the salt randomly changed each time then the license string would be different as well so even if the application.cfc was reverse engineered, the license string would never be the same.
Now to oput the theory into practice ;)
That sounds pretty cool!
great article!thanks , BEN.
And, it should also be worth pointing out that in ColdFusion 10 (public beta), there is now an in-built method for accessing the application data - getApplicationMetaData().
You should have a like button on your articles. I like the "undocumented part" :)
Thank you so much for being on top of things and making it much easier for us.