Credit for this article goes to a discovery by Martin Franklin. Thanks to a comment from him, I discovered something that may be of major importance to folks doing Ajax development on ColdFusion 8 boxes. If you do any work on a ColdFusion 8 box and do not have control over the Administrator settings, beware of the Secure Prefix setting.
About two years ago I blogged about ColdFusion 8 security features. One of them is JSON Prefixes. This is the ability to prefix all JSON results (generated by CFC, returnFormat=json) with a prefix. What's cool about this feature is that all the front end stuff ColdFusion uses will recognize this setting and automatically strip the prefix before processing the result.
What isn't so cool about this feature is that if you aren't using ColdFusion 8's front end AJAX stuff, then this can really trip you up. Imagine you've done all your work locally before pushing the code up to a shared host. All of a sudden your code stops working. It may be a good idea to pop open Firebug and look for something in front (like the default prefix, //) of the JSON response.
Here is a simple example:
<html>
<head>
<script src="jquery/jquery.js"></script>
<script>
$(document).ready(function() {
$("#submitBtn").click(function() {
var value = $("#number").val()
$.getJSON("test.cfc?method=double&returnFormat=json",{number:value},function(d) {
console.log(d)
})
})
})
</script>
</head>
<body>
<input type="text" id="number"> <input type="submit" id="submitBtn" value="Double">
</body>
</html>
Nothing too complex here. I've got a form with one input. When you hit the button, I run an AJAX request to a CFC method that will double the response. The CFC method is just:
<cffunction name="double" access="remote" returnType="any" output="false">
<cfargument name="number" required="true" type="any">
<cfif isNumeric(arguments.number)>
<cfreturn 2*arguments.number>
<cfelse>
<cfreturn 0>
</cfif>
</cffunction>
If you run the code (wrap the cffunction with a CFC of course) it should work just fine. Now go to your ColdFusion Admin, Settings page, and enable the Prefix:

Rerun your code and you will see... nothing. (To be clear, my code did nothing visual with the response except to log it to Firebug, so even before you 'saw' nothing unless you had Firebug open.) I modified my JavaScript a bit to add a global error handler (first time trying this, pretty impressed by how easy it was):
$.ajaxSetup({
error:function(req,textstatus,errorThrown) {
console.log(textstatus)
}
})
Running the page again, I now saw this in the console: parseerror.
Luckily there is a simple fix. You can override the setting (don't forget it can be set in the Application.cfc file as well) by adding the secureJson attribute to the function:
<cffunction name="double" access="remote" returnType="any" output="false" secureJSON="false">
This correctly disabled the prefix and my code worked fine again.
Definitely keep this in mind if you are deploying to machines you don't have 100% control over, or, if things seem to break down when you deploy. (Of course, the first thing to check is for the onRequest method in an Application.cfc file. Sure hope Adobe fixes that in CF9.)
Archived Comments
Are you saying that adding secureJSON="true" fixed the problem? I'm puzzled because you say that "disabled the prefix". Shouldn't that be secureJSON="false"?
Typo. Sorry. Fixing now!
If you knew the secureJSON parameter was set, couldn't you strip the first X characters from the return string (assuming you knew the prefix)?
Right, if you knew, and expected it, you could. You wouldn't use getJSON, since jQuery expects a JSON response. You would just use get or post, strip the char, and then evaluate() the result.
Guessing you are referring to the onRequest problem that prevents CFCs from being invoked properly because most of us just do something like the following inside of onRequest:
<cfinclude template="#arguments.targetPage#" />
I've been thinking about this lately and why can't we just test to see if the extension is CFC and if it is, cfinvoke the component specified by #arguments.targetPage# and the method specified by URL.method and then pass in an argumentCollection="#url#"?
Has anyone tried anything like that? If so, has it failed? I haven't tested this myself but probably will be soon.
If it does work, then I don't think Adobe needs to fix anything since it is working as should be expected.
Just some random thoughts.
@Greg, you cannot invoke the CFC - you don't know what arguments were passed. The workaround for onRequest() and CFCs is to structDelete() it from both THIS and VARIABLES scopes inside onRequestStart(). Ray blogged this some time ago.
SC is right. You can find an example here:
http://www.coldfusionjedi.c...
And to be fair, I learned the technique from Sean so he gets the credit.
I was being a lazy blogger at the time :)
@Sean, @Ray, thanks for the reply. I've been using the structDelete method for a while now but kept thinking there must be some other way to do it.
I just threw together some sample code that does successfully invoke a component inside the onRequest method and pass any arbitrary arguments specified in the URL. This code could be expanded to structAppend the Form values as well in order to grab paramaters from either scope.
Right as I was writing it though I realized it won't work for a lot of the advanced ColdFusion 8 Ajax stuff since it won't convert the return values of the functions back to JSON or whatever returnFormat may be specified.
As well, it opens a security vulnerability because the component is now being executed from within the application so any function, not just those with access="remote" will also be accessible through the URL.
Could be beefed up though to check the metadata, only execute remote functions and maybe automatically grab singletons from a factory (LightWire or ColdSpring). Grabbing the singletons from the factory is what made me think of trying this way in the first place.
If you're interested in the code at all just drop me a line at greg (at) stevens (dot) pro and I'll be more than happy to send it over. Would post it somewhere but don't have an active website up right now.
Thanks again guys, keep up the great work, been reading your stuff for years now and am always amazed at the wealth of information!
Follow up you guys may be interested in:
http://www.insideria.com/20...
What's cool is that you could literally drop this function into a site and fix this issue client side in a heartbeat.
Thanks Ray ...
I would have been pulling my hair out for quite a while on this ... :)