Debugging error output isn't restricted to the IPs specified to receive debugging output in certain cases.
This is an issue that has been around since at least ColdFusion 9, as far as I know.
Within CFAdmin, we have disabled the global error template (/CFIDE/administrator/templates/secure_profile_error.cfm) in order to enable error debug output for our debugging-enabled IPs. The problem is that the template that dumps out error information is loaded and processed regardless of whether or not the user's IP is in the debugging IP list. The "normal" way to get around this, as far as I know, is to specify an error template within your application. For example, we do something along the lines of:
<CFIF NOT isDevIP> <CFERROR TYPE="Exception" TEMPLATE="ErrorTemplate.cfm"> </CFIF>
However, this doesn't catch everything. Exceptions that occur prior to the <CFERROR> tag being processed will still result in all users seeing the debugging error output regardless of their IP address. This means you need to have the <CFERROR> tag near the beginning of each request (including AJAX requests) to minimize the potential for exceptions to be generated before the tag is processed.
The real trick, however, is that certain types of exceptions will be triggered before the <CFERROR> tag is processed regardless of where they are in the code. Consider the following:
<CFERROR TYPE="Exception" TEMPLATE="ErrorTemplate.cfm">
Blah blah blah
The unclosed <CFIF> tag is parsed before the <CFERROR> tag is processed, and all users will see the error. (Invalid CFML construct found at line ...). This can lead to code leakage as the error detail template includes code segments, line numbers, and stacktraces (if enabled in CFAdmin).
On the other hand, something like this behaves as expected:
<CFERROR TYPE="Exception" TEMPLATE="OnError.cfm">
Blah blah blah
The OnError.cfm template is loaded instead of the debugging error output being output to the screen. You can combine this with a <CFIF> check against the user's IP being in the debugger IP list to achieve the desired result, but only for exceptions that are triggered after <CFERROR> is processed.
To work around this in the past, I edited the detail.cfm exception template at, for example, \ColdFusion9\wwwroot\WEB-INF\exception\detail.cfm , and made it fist read the neo-debug.xml file (where CFAdmin stored the debug IP list) and check the user's IP. If the user's IP was not in the iplist in neo-debug.xml, then I simply ran a <CFABORT> to prevent any leakage from occurring. This also worked for CF10.
<CFWDDX ACTION="WDDX2CFML" INPUT="#XMLPARSE('C:\Coldfusion9\lib\neo-debug.xml')#" OUTPUT="neodebugxmlwddx">
<CFIF NOT LISTFIND(neodebugxmlwddx.iplist, CGI.REMOTE_ADDR)><CFABORT></CFIF>
However, in CF2016, the detail.cfm template isn't the same. In fact, it's encoded entirely differently and I can't properly edit it. (ColdFusion Builder won't even open it.)
1) Is there a way to edit the detail.cfm or other exception templates for CF2016 to achieve what I want? By default, they're located at C:\ColdFusion2016\cfusion\wwwroot\WEB-INF\exception\ , I believe.
2) If not, is there another way to make them respect the debugging IP lists defined in CFAdmin?
3) If not, is there some other way to allow specific IPs to see debugging output (including for exceptions), but to restrict other IPs from ever seeing it? Using a global error template isn't an option unless there's a way to modify that template to call the regular template (using the same IP check as above) and properly pass all the error information to it.
Copy link to clipboard
I've found a workaround.
1) Use the "Site-wide Error Handler" in CF Administrator (Server Settings, Settings, Site-wide Error Handler).
2) In the specified template, check against the IPs in the neo-debug XML file (\cfusion\lib\neo-debug.xml under the CF installation directory). (See the previous post and the CFWDDX call.)
3a) For IPs not in the neo-debug.xml file, show our generic error template.
3b) For IPs in the neo-debug.xml file, simply include the detail.cfm file ( \cfusion\wwwroot\WEB-INF\exception\detail.cfm under the CF installation directory).
If you change the "Enable Request Debugging Output" setting, make sure your custom template is still defined for the "Site-wide Error Handler".
In my testing, this achieves exactly what we want:
CFError still works as before and handling can be customized per site/application/whatever.
Errors that cause processing to halt before CFError is processed are handled by the "Site-wide Error Handler" template. Debugging IP Addresses we set in CF Administrator get redirected to the generic template with the info they expect. Everyone else gets a generic message.
For me, I either set the CFERROR immediately or I use the application onError event which seems to install almost immediately. The only time errors happen before my trap is installed is a strange syntax error in application.cfc and it can't compile or if the CF service does not execute for whatever reason. Now I have had issues with my error handler using application and/or session variable that did not exist - like my logging object. For this I've learned to wrap a last ditch try/catch around my error processing logic. Example (sorry for typos, this is more pseudo code):
<cfset variables.originalError=error />
<h1>We're Truly Hosed!</h1>
<cfdump label="Secondary Error" var="#cfcatch#" />
<cfdump label="Original Error" var="#variables.originalError#" />
Now I have had issues with my error handler using application and/or session variable that did not exist - like my logging object.
I've noticed that onError() doesn't always have access to variables set within onRequestStart() or onRequest(), so I just copied/pasted the variables being set from onRequestStart() and onRequest() into onError(). It's a bummer that I have to remember to update the ones in onError() if changed in onRequestStart() or onRequest(), but it works.