Copy link to clipboard
Copied
Good morning,
We used CF2021 and we installed the lates update 17. Started having issues with our login system in one box losing the cfathentication session var.
I created a test login to trace the issue in the same box, because in other box works fine. The security team applied some stigs to the box lately and not sure if that is afecting the browser.
When user login the first time the cfauthentication is not showing.
Here is the application.cfc
<cfcomponent output="false" hint="I define the application settings and event handlers.">
<cfscript>
//Define the application settings.
this.clientManagement = false;
// define the cflogin storage
this.loginStorage = "session";
this.name = listLast(getDirectoryFromPath(getCurrentTemplatePath()), "\");
this.applicationTimeout = createTimeSpan( 0, 0, 0, 10 );
this.sessionManagement = true;
this.sessionTimeout = createTimeSpan( 0, 0, 5, 0 );
this.setClientCookies = true;
this.secureJSONPrefix = "";
</cfscript>
<!--- Define the request settings. --->
<cfsetting showdebugoutput="false"/>
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false" hint="I initialize the application.">
<cfscript>
// root and upload folder
application.root_folder = this.name;
application.upload_folder = Left(getDirectoryFromPath(getBaseTemplatePath()), FindNoCase('\', getDirectoryFromPath(getBaseTemplatePath()), FindNoCase(application.root_folder, getDirectoryFromPath(getBaseTemplatePath())))) & "UPLOAD_" & uCase(this.name);
application.absolute_folder = Left(getDirectoryFromPath(getBaseTemplatePath()), FindNoCase('\', getDirectoryFromPath(getBaseTemplatePath()), FindNoCase(application.root_folder, getDirectoryFromPath(getBaseTemplatePath()))));
</cfscript>
<!--- Initialize the application settings. --->
<cfset application.dateInitialized = now() />
<cfset application.debug = debug />
<cfset application.sqlRegEx = "<[^>]*>|insert|select|delete|update|create|drop|alter|&|%|" />
<!--- Return true so that the page can load. --->
<cfreturn true />
</cffunction>
<cffunction name="onApplicationEnd" output="no" returnType="void">
<cfargument name="applicationScope" required="true" />
</cffunction>
<cffunction name="onRequestStart" output="true" returnType="boolean">
<cfargument name="thePage" type="string" required="true" />
<cfif NOT isDefined("session.loggedIn")>
<cfset session.loggedIn = false />
</cfif>
<cfreturn true />
</cffunction>
<cffunction name="onSessionStart" access="public" returntype="void" output="false" hint="I initialize the session.">
<!--- Initialize the session settings. --->
<cfset session.dateInitialized = now() />
<cfset session.id = createUuid() />
<cfif NOT isDefined("session.loggedIn")>
<cfset session.loggedIn = false />
</cfif>
<!--- Return out. --->
<cfreturn />
</cffunction>
<cffunction name="onRequest" returnType="void">
<cfargument name="thePage" type="string" required="true" />
<!--- <cfset applicationStop() /> --->
<cflogin applicationtoken="#this.name#" idletimeout="#this.sessionTimeout#">
<cfif (isDefined("form.j_username") and len(trim(form.j_username)) GT 0 and isDefined("form.j_password") and len(trim(form.j_password)) GT 0)>
<!--- check for SQL injection and script since log in form is semi-public --->
<cfset cflogin.name = REReplaceNocase("#trim(cflogin.name)#", application.sqlRegEX, "", "ALL") />
<cfset cflogin.password = REReplaceNocase("#trim(cflogin.password)#", application.sqlRegEX, "", "ALL") />
<cfif authenticateUser(cflogin.name, cflogin.password)>
<cfset session.loggedIn = true />
<cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="SUPER USER">
<cfelse>
<cfset variables.loginError = "Username and/or Password is Invalid." />
</cfif> <!--- END IF: authenticateUser() --->
</cfif>
<!--- <cfset application.debug(session)/><cfabort> --->
<cfif isDefined("session.loggedIn") AND NOT session.loggedIn>
<cfinclude template="login.cfm" />
<cfabort />
<cfelse>
<cfinclude template="index.cfm" />
</cfif>
</cflogin>
</cffunction>
<cffunction name="authenticateUser" output="no" returntype="boolean">
<cfargument name="userName" required="yes" type="string" />
<cfargument name="passWord" required="yes" type="string" />
<cfset var returnValue = FALSE />
<cfset var qryAuthUser = "" />
<cfquery name="qryAuthUser" datasource="myDatabase">
SELECT *
FROM users u
WHERE u.user_id = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#trim(arguments.userName)#" />
AND u.user_password = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#hash(trim(arguments.passWord))#" />
</cfquery>
<cfif qryAuthUser.recordCount eq 1>
<cfset returnValue = TRUE />
</cfif>
<cfreturn returnValue />
</cffunction>
<cffunction name="debug" access="public" output="true" returntype="void">
<cfargument name="input" required="No" default="" />
<cfset var debugFile = '#application.absolute_folder#debug.cfm' />
<cfset var debugInfo = "" />
<cfsavecontent variable="debugInfo">
<p><strong>DEBUGGING</strong>: <cfoutput> #dateFormat(now(),'mm/dd/yyyy')# #timeFormat(now(), 'HH:mm:ss tt')# </cfoutput><br>
<cfdump var="#arguments.input#" label="custom" format="html">
<cfdump var="#form#" label="form" format="html">
<cfdump var="#url#" label="url" format="html">
<cfdump var="#cgi#" label="cgi" format="html">
<cfdump var="#application#" label="application" format="html">
</cfsavecontent>
<cffile action="WRITE" file="#debugFile#" output="#debugInfo#" />
</cffunction>
</cfcomponent>
And login.cfm
<!DOCTYPE html>
<cfsilent>
<cfparam name="session.lastLoginDate" default="" type="string">
<cfparam name="variables.user_id" default="" type="string">
<cfparam name="FORM.j_username" type="string" default="" />
<cfparam name="FORM.j_password" type="string" default="" />
</cfsilent>
<!--- <cfset application.debug(session)/><cfabort>--->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><cfoutput>Test Site</cfoutput></title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=10, user-scalable=yes">
</head>
<body>
<h1>
Application Login
</h1>
<form action="#CGI.script_name#" method="post">
<label>
Username:
<input type="text" name="j_username" size="20" />
</label>
<br />
<br />
<label>
Password:
<input type="password" name="j_password" size="20" />
</label>
<br />
<br />
<input type="submit" value="Login" />
</form>
</body>
</html>
and the Index.cfm
<cfoutput>
<cfset application.debug(session)/>
<cfif isDefined("session.loggedIn") and session.loggedIn >
<h1>We are in </h1>
</cfif>
<h1>
Application And Session Overview
</h1>
<p>
Application initialized:
#dateDiff(
"s",
application.dateInitialized,
now()
)#
seconds ago.
</p>
<p>
Session initialized:
#dateDiff(
"s",
session.dateInitialized,
now()
)#
seconds ago.
</p>
</cfoutput>
The first time I do the login the session var cfathentication is not showing
If I refresh the browser the session var shows.
What am I doing wrong? Any ideas?
Thanks in advanced.
Johnny
Copy link to clipboard
Copied
Within seconds of reading your post, I saw something that stopped me. It is this code:
this.applicationTimeout = createTimeSpan( 0, 0, 0, 10 );
this.sessionTimeout = createTimeSpan( 0, 0, 5, 0 );
This doesn't make sense for at least two reasons:
this.applicationTimeout = createTimeSpan( 0, 0, 3, 0 );​
this.sessionTimeout = createTimeSpan( 0, 0, 0, 30 );​
Copy link to clipboard
Copied
Thanks for your reply and help.
I missed that, i fixed the code per your suggestion, do applicationStop, but the behavior still the same.
Best, Johnny
Copy link to clipboard
Copied
Given the login code
<cfif (isDefined("form.j_username") and len(trim(form.j_username)) GT 0 and isDefined("form.j_password") and len(trim(form.j_password)) GT 0)>
<!--- check for SQL injection and script since log in form is semi-public --->
<cfset cflogin.name = REReplaceNocase("#trim(cflogin.name)#", application.sqlRegEX, "", "ALL") />
<cfset cflogin.password = REReplaceNocase("#trim(cflogin.password)#", application.sqlRegEX, "", "ALL") />
<cfif authenticateUser(cflogin.name, cflogin.password)>
<cfset session.loggedIn = true />
<cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="SUPER USER">
<cfelse>
<cfset variables.loginError = "Username and/or Password is Invalid." />
</cfif> <!--- END IF: authenticateUser() --->
</cfif>
<cfif isDefined("session.loggedIn") AND NOT session.loggedIn>
<cfinclude template="login.cfm" />
<cfabort />
<cfelse>
<cfinclude template="index.cfm" />
</cfif>
here's a suggestion for improvement:
<cfif (isDefined("form.j_username") and len(trim(form.j_username)) GT 0 and isDefined("form.j_password") and len(trim(form.j_password)) GT 0)>
<!--- check for SQL injection and script since log in form is semi-public --->
<cfset cflogin.name = REReplaceNocase("#trim(cflogin.name)#", application.sqlRegEX, "", "ALL") />
<cfset cflogin.password = REReplaceNocase("#trim(cflogin.password)#", application.sqlRegEX, "", "ALL") />
<cfif authenticateUser(cflogin.name, cflogin.password)>
<cfset session.loggedIn = true />
<cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="SUPER USER">
<cfelse>
<cflogout>
<cfset session.loggedIn = false>
<cfset variables.loginError = "Username and/or Password is Invalid." />
</cfif> <!--- END IF: authenticateUser() --->
</cfif>
<cfif NOT isDefined("session.loggedIn") OR NOT session.loggedIn>
<cfinclude template="login.cfm" />
<cfabort />
<cfelse>
<cfinclude template="index.cfm" />
</cfif>
Copy link to clipboard
Copied
Yeah, @BKBK 's concern is valid. What's more, that's kind of a big deal to have an error like that. I recommend you hire someone to review your authentication code process in greater detail than most of us are willing to do for free.
Copy link to clipboard
Copied
While someone else may see something more specific for you based on all that code, I'll ask some potentially clarifying questions:
1) What update where you on before applying update 17? That could be important, especially if you had been on u12 or 13, I as updates 13 and 14 had significant changes potentially affecting backward compatibility. You can assess what update you were on previously using the hf-updates folder and its logs.
And you'd want to check both machines, of course, as that may relate to how they differ for you.
2) You should check also the Java args for each cf instance, as those updates 13 and 14 also offered new jvm args to optionally revert what the updates had changed. It may be that an arg is on one and not the other.
3) You refer to the first request not having a needed var. I'm assuming you mean the first request AFTER login, right?
4) And you refer to the missing var as cfathentication. Besides that being a typo (no "u"), neither dump shows that. I'll assume you meant to refer instead to the one starting with "cfauthorization".
5) You may want to do more to know the flow of control through the different decision points in the code. That may help you to know how that flow differs on the two instances.
6) Pay particular attention to what comes back from the cfquery. That may differ for reasons you'd not anticipate by just eyeballing the code.
But again, maybe someone else will see something more helpful for you from the code alone.
Copy link to clipboard
Copied
Doh! Bkbk's reply came in while I was writing mine (but I didn't see his until after submitting mine). If that gets you going, great. If not, I leave mine here for consideration.
Copy link to clipboard
Copied
I found some difference when I look close in the JVM settings.
Anything that will affect?
Thanks
Copy link to clipboard
Copied
I'd suspect the last one on the "issue" machine. That arg was introduced in cf10, to optionally disable the "session fixation" protection that was added in that release, and since. (You can google that phrase to learn more as it's a generic it issue and not specific to cf.) And yes, I could see that affecting the cflogin/cfauthenticate processing, but I as those have to do with processing session tokens.
You should test with that removed from there or added to the other. I realize you'd not want to change a prod instance. Hopefully you can recreate all this in a test setup, using the free cf developer edition or trial.
Or maybe someone else will have a different thought.
One last question: check the cf admin of each instance on the settings> "memory variables" page, specifically the "j2ee sessions" option. Is it the same on both machines?
Copy link to clipboard
Copied
I missed this, thanks.
I remove the session fixation option and bounce the cf service.
"One last question: check the cf admin of each instance on the settings> "memory variables" page, specifically the "j2ee sessions" option. Is it the same on both machines? "
Yes, both are the same.
Thanks again !
Copy link to clipboard
Copied
Thanks for your reply and help.
1. It was update 16.
2. Using java jdk-11.0.24. No changes in JVM arguments, they are the same comparing to a working box.
3. Correct, after the login.
4. Yes, "cfauthorization".
5. Ok, the code is the same.
6. The data comes ok from the query, that was the first thing I checked.
Any other ideas?
Johnny
Copy link to clipboard
Copied
Just discover one more behavior.
This issue shows if I run localhost or 127.0.0.1 in the local box. If I run the same code in the same box using the site link from the other box, the code works.
Any ideas how can I trace the issue?
Thanks! Johnny
Copy link to clipboard
Copied
Copy link to clipboard
Copied
1. yes.
2. I sent the image with the differences. Not sure if any of those paramenters will make the difference.
5. That is what I have issue with. I cannot figure out when is the cfauthorization disappearing.
Thanks again.
Copy link to clipboard
Copied
Suggestion to further improve the login code:
<cfif (isDefined("form.j_username") and len(trim(form.j_username)) GT 0 and isDefined("form.j_password") and len(trim(form.j_password)) GT 0)>
<cfset var un=trim(form.j_username)>
<cfset var pw=trim(form.j_password)>
<cflogin applicationtoken="#this.name#" idletimeout="#this.sessionTimeout#">
<!--- check for SQL injection and script since log in form is semi-public --->
<cfset un = REReplaceNocase(un, application.sqlRegEX, "", "ALL") />
<cfset pw = REReplaceNocase(pw, application.sqlRegEX, "", "ALL") />
<cfif authenticateUser(un, pw)>
<cfset session.loggedIn = true />
<cfloginuser name="#un#" password="#pw#" roles="SUPER USER">
<cfelse>
<cflogout>
<cfset session.loggedIn = false>
<cfset variables.loginError = "Username and/or Password is Invalid." />
</cfif>
</cflogin>
</cfif>
<cfif NOT isDefined("session.loggedIn") OR NOT session.loggedIn>
<cfinclude template="login.cfm" />
<cfabort />
<cfelse>
<cfinclude template="index.cfm" />
</cfif>
Copy link to clipboard
Copied
I really appreciate your input.
Thanks!
Copy link to clipboard
Copied
Question: what do you use for session storage? Is it the standard EHcache or do you use an external system like Redis?
We had something similar happen with CFLogin a while back when we switched to remote Redis cache for sessions.
Copy link to clipboard
Copied
Thanks for reply and help.
We used sessions for manage user permissions on our app, we show/hide functionality based on permissions.
We also have a history tracking systems that we passed the authencted user id into database triggers.
Copy link to clipboard
Copied
@jfb00 , the code suggestion I gave you is relevant to the issue. What happens when you apply it?
Copy link to clipboard
Copied
You got it, my demo code is working. I will check my real site.
What is the issue? can you explain?
Thanks!
Copy link to clipboard
Copied
What is the issue? can you explain?
By @jfb00
Sure. I shall explain.
The suggestios
<cflogout>
<cfset session.loggedIn = false>​
<cfif NOT isDefined("session.loggedIn") OR NOT session.loggedIn>​
in place of
<cfif isDefined("session.loggedIn") AND NOT session.loggedIn>
Copy link to clipboard
Copied
Thanks for your reply and help.
I fixed the app cfc code the way you suggested.
<cfcomponent output="false" hint="I define the application settings and event handlers.">
<cfscript>
//Define the application settings.
this.clientManagement = false;
// define the cflogin storage
this.loginStorage = "session";
this.name = listLast(getDirectoryFromPath(getCurrentTemplatePath()), "\");
this.applicationTimeout = createTimeSpan( 0, 0, 3, 0 );
this.sessionManagement = true;
this.sessionTimeout = createTimeSpan( 0, 0, 0, 30 );
this.setClientCookies = true;
this.secureJSONPrefix = "";
</cfscript>
<!--- Define the request settings. --->
<cfsetting showdebugoutput="false"/>
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false" hint="I initialize the application.">
<cfscript>
// root and upload folder
application.root_folder = this.name;
application.upload_folder = Left(getDirectoryFromPath(getBaseTemplatePath()), FindNoCase('\', getDirectoryFromPath(getBaseTemplatePath()), FindNoCase(application.root_folder, getDirectoryFromPath(getBaseTemplatePath())))) & "UPLOAD_" & uCase(this.name);
application.absolute_folder = Left(getDirectoryFromPath(getBaseTemplatePath()), FindNoCase('\', getDirectoryFromPath(getBaseTemplatePath()), FindNoCase(application.root_folder, getDirectoryFromPath(getBaseTemplatePath()))));
</cfscript>
<!--- Initialize the application settings. --->
<cfset application.dateInitialized = now() />
<cfset application.debug = debug />
<cfset application.sqlRegEx = "<[^>]*>|insert|select|delete|update|create|drop|alter|&|%|" />
<!--- Return true so that the page can load. --->
<cfreturn true />
</cffunction>
<cffunction name="onApplicationEnd" output="no" returnType="void">
<cfargument name="applicationScope" required="true" />
</cffunction>
<cffunction name="onRequestStart" output="true" returnType="boolean">
<cfargument name="thePage" type="string" required="true" />
<cfif NOT isDefined("session.loggedIn")>
<cfset session.loggedIn = false />
</cfif>
<cfreturn true />
</cffunction>
<cffunction name="onSessionStart" access="public" returntype="void" output="false" hint="I initialize the session.">
<!--- Initialize the session settings. --->
<cfset session.dateInitialized = now() />
<cfset session.id = createUuid() />
<cfif NOT isDefined("session.loggedIn")>
<cfset session.loggedIn = false />
</cfif>
<!--- Return out. --->
<cfreturn />
</cffunction>
<cffunction name="onRequest" returnType="void">
<cfargument name="thePage" type="string" required="true" />
<!--- <cfset applicationStop() /> --->
<cfif (isDefined("form.j_username") and len(trim(form.j_username)) GT 0 and isDefined("form.j_password") and len(trim(form.j_password)) GT 0)>
<cfset var un=trim(form.j_username)>
<cfset var pw=trim(form.j_password)>
<cflogin applicationtoken="#this.name#" idletimeout="#this.sessionTimeout#">
<cfset un = REReplaceNocase(un, application.sqlRegEX, "", "ALL") />
<cfset pw = REReplaceNocase(pw, application.sqlRegEX, "", "ALL") />
<cfif authenticateUser(un, pw)>
<cfset session.loggedIn = TRUE />
<cfloginuser name="#un#" password="#pw#" roles="SUPER USER">
<cfset loginUser(un)/>
<cfelse>
<cflogout>
<cfset session.loggedIn = false>
<cfset variables.loginError = "Username and/or Password is Invalid." />
</cfif> <!--- END IF: authenticateUser() --->
</cflogin>
</cfif>
<!--- <cfset application.debug(session)/><cfabort> --->
<cfif not isDefined("session.loggedIn") AND NOT session.loggedIn>
<cfinclude template="login.cfm" />
<cfabort />
<cfelse>
<cfinclude template="index.cfm" />
</cfif>
</cffunction>
<cffunction name="authenticateUser" output="no" returntype="boolean">
<cfargument name="userName" required="yes" type="string" />
<cfargument name="passWord" required="yes" type="string" />
<cfset var returnValue = FALSE />
<cfset var qryAuthUser = "" />
<!--- <cfquery name="qryAuthUser" datasource="myDatabase">
SELECT *
FROM users u
WHERE u.userid = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#trim(arguments.userName)#" />
AND u.userpass = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#hash(trim(arguments.passWord),"MD5", "UTF-8")#" />
</cfquery>
<cfif qryAuthUser.recordCount eq 1>
<cfset returnValue = TRUE />
</cfif> --->
<cfset returnValue = TRUE />
<cfreturn returnValue />
</cffunction>
<cffunction name="loginUser" output="no" returntype="void">
<cfargument name="userName" required="yes" type="string" />
<cfset var updUserTracking = "" />
<cfset var insUserTracking = "" />
<cfset session.loggedIn = TRUE />
<cfset variables.loggedIn = session.loggedIn />
<!--- <cfquery name="updUserTracking" datasource="myDatabase">
UPDATE users
SET last_succ_log = SYSDATE,
date_mod = sysdate,
mod_by = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#trim(arguments.userName)#" />
WHERE user_id = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#trim(arguments.userName)#" />
</cfquery> --->
<cfset application.debug([GetAuthUser(),session])/><cfabort/>
</cffunction>
<cffunction name="debug" access="public" output="true" returntype="void">
<cfargument name="input" required="No" default="" />
<cfset var debugFile = '#application.absolute_folder#debug.cfm' />
<cfset var debugInfo = "" />
<cfsavecontent variable="debugInfo">
<p><strong>DEBUGGING</strong>: <cfoutput> #dateFormat(now(),'mm/dd/yyyy')# #timeFormat(now(), 'HH:mm:ss tt')# </cfoutput><br>
<cfdump var="#arguments.input#" label="custom" format="html">
<cfdump var="#form#" label="form" format="html">
<cfdump var="#url#" label="url" format="html">
<cfdump var="#cgi#" label="cgi" format="html">
<cfdump var="#application#" label="application" format="html">
</cfsavecontent>
<cffile action="WRITE" file="#debugFile#" output="#debugInfo#" />
</cffunction>
</cfcomponent>
Now, when I called the function loginUser() - line 89, the GetAuthUser() variable is gone in the function when I check (line 147).
Why the GetAuthUser() var is gone?
Thanks, Johnny
Copy link to clipboard
Copied
I used GetAuthUser() in my real site, later in the header page after the login.
The GetAuthUser() value is empty, any ideas why? Is this part of the security fixed?
Thanks, Johnny
Copy link to clipboard
Copied
Johnny, in case it's gotten lost in all the threads here, I offered an observation a few hours ago that may be useful for you, based on the jvm args you'd shared.
Copy link to clipboard
Copied
I used GetAuthUser() in my real site, later in the header page after the login.
The GetAuthUser() value is empty, any ideas why? Is this part of the security fixed?
By @jfb00
Your code is much improved, and should work. The problem you are getting with getAuthUser() is unlikely to be related to any ColdFusion settings or fixes.
I think the problem is caused because the copy of the debug function that the application uses is cached in application scope. Therefore the application initializes the function just once, when the application begins, and that's it.
However, ColdFusion stores the function itself in memory in the variables scope. It seems to me that that is the copy of the function that the application needs.
Secondly, recent updates of ColdFusion pay greater attention than before to scoping.
Putting these 2 points together, I would make the following additional suggestions:
<cfset application.debug = debug />​
to
<!--- 'Variables' scoping important --->
<cfset application.debug = variables.debug />
In fact, let's suppose you don't intend to use application.debug anywhere else in the application, say in CFM or CFC pages. If so, I would suggest you delete that line altogether. Then replace every call
application.debug(xxx)
with
variables.debug(xxx)