Session Cookies and Application.cfm - cookies

This code in the Application.cfm (I know it should probably be .cfc, but this is some old code dating back to MX) for cookies used to work just fine on CF8 and CF9 - but I moved this to a local directory using CF10 Developer edition and it did not work until I commented out that block. Here's the error when reaching the index.
The system has attempted to use an undefined value, which usually indicates a programming error, either in your code or some system code.
Null Pointers are another name for undefined values.
The error occurred in C:/ColdFusion10/cfusion/wwwroot/TFT/Application.cfm: line 3
1 : <!--- APPLICATION settings --->
2 : <cfif IsDefined("cfid")>
3 : <cfcookie name="cfid" value="#cfid#" expires="NOW">
4 : <cfcookie name="cftoken" value="#cftoken#" expires="NOW">
5 : </cfif>
This is the current code in Application.cfm:
<!--- APPLICATION settings --->
<!--- 5/1/13 removed cookies temporarily
<cfif IsDefined("cfid")>
<cfcookie name="cfid" value="#cfid#" expires="NOW">
<cfcookie name="cftoken" value="#cftoken#" expires="NOW">
</cfif>--->
<!--- Define the application parameters--->
<cfapplication name="TFTAdmin" clientmanagement="Yes"
sessionmanagement="Yes"
setclientcookies="No"
sessiontimeout="#CreateTimeSpan('0','4','0','0')#"
applicationtimeout="#CreateTimeSpan('0','4','0','0')#">
<!--- Create cookies that disappear when the browser closes as to increase security --->
<cflock scope="session" type="readonly" timeout="5">
<cfcookie name="cfid" value="#session.cfid#">
<cfcookie name="cftoken" value="#session.cftoken#">
</cflock>
EDIT: There's more code in this file - but it seems irrelevant.

What happens if you properly scope your variables? cfid could be defined in the variables scope as a null value.
<cfif structKeyExists(session,"cfid")>
<cfcookie name="cfid" value="#session.cfid#" expires="NOW">
<cfcookie name="cftoken" value="#session.cftoken#" expires="NOW">
</cfif>

Because you were on a new server I suspect that you managed to get your cookies into a state where the didn't have values that made sense.
I'm not sure fixing the code is important anyway, because it appears to be doing something nonsensical. But a quick fix of the code would be to do this:
<cfif IsDefined("cfid")>
<cfcookie name="cfid" value="" expires="NOW">
<cfcookie name="cftoken" value="" expires="NOW">
</cfif>
It's still only testing for cfid but it's not setting the values of the cookies. The values don't matter because the code is expiring the cookies.
The reason I said the code was nonsensical is because the Cookie scope is part of the scope evaluation order. So what the code as a whole is doing is saying "if cookies exist, remove them and then set new cookies with new values." So users will get a fresh session on every page refresh. That is the same as not having any session management in the first place. So you might as well set sessionmanagement="false" and remove both cookie blocks of code.
It's possible, tho unlikely, that this code came about because someone wanted to provide a little bit of extra security by not allowing the session to be changed via URL/form variables, thus limiting session hijacking. However the way that it was implemented doesn't solve that issue either.

Related

Session variable not found

for a long period of time I have an issue with Session variables. I'm looking for some pointers or directions to address this problem. I try to explain what is happening and I understand that the information provided isn't sufficient to understand what is happening, but I'm trying to solve this and it's driving me nuts :-)
I have several Lucee webapplications (Lucee: 5.3.7.48) which are also available as Cordova app. Error messages are sent to my by e-mail. On a daily bases I receive about 100 messages that the session variable can not be found.
[APP] is a session variable, set in the file index.cfm.
<cfparam name="SESSION.auth.app" default="">
In line 592 there is something like
<cfif session.auth.app is 1>do something</cfif>
I don't want to focus on line 592, the real problem is that the session variable is/gets lost. What happens next is that the user is redirect to the login page (login.cfm), because the session is lost and then the problem repeats, it's a kind of loop. The application has a save username/password option.
This all happens when the application is running in the background, like the Cordova app running in the background. I know this because I reached out to a user when receiving 20 error messages, and he told me that I wasn't using the application at the time of the error messages.
In conclusion I measure a user when he is using the login.cfm page. As you van see in the image there is a peak in usage on March 16th, which has to do with the problem described.
I understand that I provided not much useful information to go on, but can someone give me some directions how to approach this problem?
UPDATE April 14th
I have changed the way session vars are set and followed the suggestions in the reactions.
In the application.cfc I have add:
<cffunction name="onSessionStart" access="public" returntype="void" output="false" hint="I fire when a new session begins.">
<cfset SessionRotate()>
<cfset SESSION.app = ''>
<cfset SESSION.device = ''>
<cfset SESSION.app_file_url = 'window.open'>
</cffunction>
Restarted Lucee just the be sure. But still the same error messages, APP doesn't exist. After some additional searching I found: https://www.bennadel.com/blog/1535-coldfusion-session-is-always-created-even-if-onsessionstart-fails.htm
Could this be a Lucee bug? Are do you have more suggestions to try?
In your onSessionStart function, Can you please change it to this?
<cfset session.auth = {}>
<cfset session.auth.app = ''>
I see you are checking <cfif session.auth.app is 1>do something</cfif> which should have the session.auth defined for it to work.
I hope the above helps.
Also, I'd be interested in knowing what are you dumping on the screen?

What is wrong with this CFIF structure?

I have the following at the top of a page...
<cfif isdefined("session.loggedin") and session.loggedin eq true>
<cfinclude template="includeUserInfo.cfm">
<cfinclude template="includeSideBar.cfm">
<cfelse>
<cflocation url="../sign-in.cfm">
</cfif>
When I execute the page and session.loggedin DOES equal true it executes as expected and adds the included files.
If I hit the page without logging in - I'm not being redirected to the sign in page - I'm just getting a completely blank page - zero html in the view source.
Session management is enabled in my application.cfc file
I'm not sure if what I am doing is wrong - appreciate any advice.
OK - so (as is often the case) I had missed the underlying cause of the problem - and while focussing on the imagined problem with the CFIF statement itself, missed the small cfinvoke that was before it in the code. That was trying to execute a database lookup, but failing when a user was not logged in.
swapping these around and making sure the block above is before everything else on the page has done the trick. Go me. Thanks everyone for the input.

ColdFusion security by checking ARGUMENTS.TargetPage in Application.onRequestStart?

I have a ColdFusion app in which I wish to restrict access to certain pages, based on some criteria. I am currently doing it like this, in Application.cfc:
<cffunction name="OnRequestStart" access="public" returntype="boolean" output="true">
<cfargument name="TargetPage" type="string" required="true" />
<cfif not SESSION.isAdmin and REFindNoCase("/admin",ARGUMENTS.TargetPage) >
<!--- Deny non-admin access to admin pages. --->
<cfinclude template="/notauth.cfm">
<cfreturn false />
</cfif>
<cfreturn true />
</cffunction>
My main concern is: How vulnerable is the general approach of checking TargetPage against a regex, and are there ways to improve the security of this design? Specifically, I'm concerned about avoiding "canonical representation vulnerabilities." See here.
For example, using just a REFind instead of REFindNoCase would let people slide right on through if they went to "/ADMIN/". Are there are other things to watch out for here?
I know there are other designs, like using another Application.cfc in a subfolder, or doing checks right in the page code. But I like the idea of having all my security code in one place. So please only suggest those in your answer if there's no way to do the above securely, or if it's just really a bad idea for some reason. Thanks.
I'm sure there are reams of this stuff on the internets but here is my take on it :)
They way I would solve your specific example is to maintain a database list of scripts that are restricted (a blacklist) unless you are a member of a certain group (i.e. you are an admin).
You can make this as complicated as you wish but for a simple start you could compare the full script name (CGI.SCRIPT_NAME) to a query of queries representing blacklisted pages you store in the APPLICATION scope that you loaded in onApplicationStart() called qRestrictedList.
So in onRequestStart you could do the following:
<cfquery name="qThisPageRestricted" dbtype="query">
SELECT * FROM qRestrictedList
WHERE ScriptName = '#CGI.SCRIPT_NAME#'
</cfquery>
<cfif qThisPageRestricted.recordCount and not SESSION.isAdmin>
<cfinclude template="/notauth.cfm">
<cfreturn false />
</cfif>
Even better, you can expand on this at a later date by wrapping all this in a 'authentication' CFC and creating user groups and levels, i.e. move your logic out of onRequestStart() and encapsulate it.
But as a start, storing the data in the database might be a more maintainable way for you to get this done and provide a better foundation for future changes to how your authentication works.
I hope this helps.
It may worth to make regex a bit stricter:
REFindNoCase("\/admin\/([A-Za-z_]+)\.cfm", ARGUMENTS.thePage)
A better approach would be to put an application.cfc in the /admin directory that controls access (maybe based on a SESSION variable set through logging in as an admin), and have that "child" application.cfc reference the parent one if necessary.
See this question for an example on how to do this: Extending application.cfc in a subdirectory

Is ColdFusion Scripted Linearly? Why this error?

I have received this error
Element CUSTOMERID is undefined in CLIENT.
D:\Inetpub\wwwsitecom\wwwroot\rders.cfm:296
on a page that begins with the following code:
<cfif NOT CreateObject("component","User.User").IsLoggedIn()>
<script type="text/javascript">
window.location.href='/index.cfm';
</script>
<cfabort>
</cfif>
<cfif NOT IsDefined("client.customerid")>
<cfparam name="client.customerid" default="0">
<script type="text/javascript">
alert("We're sorry.");
window.location.href="/logout.cfm";
</script>
<cfabort>
</cfif>
and on line 296
<cfinvoke component="Account" method="getAccessInfo" returnvariable="getInfo">
<cfinvokeargument name="customerid" value="#client.CustomerID#">
</cfinvoke>
The IsLoggedIn Function has this piece of code
<cfif NOT StructKeyExists(client,"customerid")>
<cfset strIsLoggedIn = 0>
</cfif>
If ColdFusion processes scripts linearly, how would it have gotten to the undefined client.customerid on line 296 without processing the first parts of the page?
If ColdFusion does not process scripts linearly, how can I prevent this error?
First, I would check that you aren't creating a variable somewhere (perhaps in an implicit scope in a <cfoutput> or <cfloop> tag) that's named client. Since CF is a late-bound language, that can change the semantics, and references to client.CustomerID will be looking in your local client variable, not the Client scope.
Secondly, if you want to do a redirect, please, please, use <cflocation> instead of doing this crazy JavaScript redirect. Remember that JavaScript is executed on the client side, and it is perfectly possible (and not even that uncommon) for browsers to have JavaScript disabled. <cflocation> results in an HTTP 3xx response being sent, which will work correctly in any browser that implements HTTP, regardless of whether or not JavaScript is enabled. It's also much more secure, since there's no chance of parts of the page being flushed to the client before the redirect.
Make sure you have client variables set up correctly in cfide and check that they are enabled in your Application.cfc file.

Override onMissingTemplate handling in Application.cfc

I want to handle a scenario where user hits a url of /somePage.cfm when that template doesn't exist and use a template from another directory. I know I can do this via rewrites in apache etc. but I don't really want to store logic in there so I gave trying to override onTemplateMissing behaviour in my Application.cfc.
It seems to be working fine in my testing but I'm worried by doing this hacky solution I'm short cutting some parts that I haven't seen yet (e.g. methods that I'm not currently using such as onSessionStart etc.) and may run into issues in the future.
Here is what I'm currently doing:
<cffunction name="onMissingTemplate">
<cfargument name="targetPage" />
<!--- Handle any templates that we're really loading from elsewhere --->
<cfif isFooTemplate(arguments.targetPage)>
<cfset onRequestStart(arguments.targetPage) />
<cfset onRequest(arguments.targetPage) />
<cfset onRequestEnd(arguments.targetPage) />
<cfreturn true />
</cfif>
<cfreturn false />
</cffunction>
Note that also in my onRequest method I'm doing further handling for templates that isFooTemplate() would return true to.
I don't think this is a hacky solution. This is what the method is for, and on returning false, ColdFusion will invoke the standard error handler you setup in the administrator if you want.
The only case were onSessionStart() hasn't run is if the user hits the onMissingTemplate() on the first ever page request. If you for some reason need the user to have a session, you can check for the existence of the session scope, since the session scope is supposed to be available in the onMissingTemplate() method and handle appropriately.
It's actually onMissingTemplate not onTemplateMissing; and this is a recommended practice, not 'hacky' at all. You're fine doing it this way.