How do I secure CFID for PCI compliance? - cookies

We've been failing our PCI scans because ColdFusion has predictable CFIDs. The exact FAIL we get is "Predictable Cookie Session IDs". Now the CFTOKEN is no longer predictable since I've configured CF to use UUID for CFTOKEN, however, the CFID is still predictable and unaffected by any changes in CF Admin.
I don't really know why the CFID being predictable is a threat, but they want us to fix it.
I have been unable to find anything on the matter by googeling, and I'm really not sure what else to do.
Has anyone else dealt with something like this? Any suggestions?
EDIT:Here is what my Application.cfc file looks like:
<cfcomponent output="false">
<cfset this.name="DatabaseOnline">
<cfset this.sessionManagement=true>
<cfset this.setDomainCookies=true>
<cfset this.setClientCookies=true>
<cfset this.sessionTimeOut=#CreateTimeSpan(0,20,0,0)#>
</cfcomponent>
And my CF admin looks like this: http://i.imgur.com/k9OZH.png
So how do I disable CFID?

Using J2EE session variables should address that problem.
To do that go to CF Administrator. Server Settings --> Memory Variables and check the 'Use J2EE session variables' check box.
You can find some more information here http://helpx.adobe.com/coldfusion/kb/predictable-cookie-session-ids-reported.html

Explain to the scanning agent that the CFID is sequential, but is not valid without a corresponding CFTOKEN cookie which is randomized. Since the session cannot be hijacked with the ID alone, it mitigates the reason for the scan failure. Their automated test assumes that the CFID cookie controls the session on its own, which is not the case. Every scanning vendor that I've worked with has accepted this as a mitigating factor and either disabled or overridden that specific test for me on CF-based sites.
Alternately, if none of the sites on the CF server use session variables, you can disable session management entirely and CF won't issue the cookies at all. If they are needed, the above explanation of how CF sessions are managed should get you through.

Related

How to secure ColdFusion cookies with HTTPOnly/ Secure attribute?

I am trying to help a company who is experiencing an issue with their ColdFusion website. The issue is a PCI scan failure due to "insecure cookies with HTTPOnly/ Secure Flag attributes".
Previously I fixed this error for 3 other cookies: JSESSIONID, CFID, CFTOKEN by editing the web.xml file; however, this time the issue is apparently with a session cookie created inside of the Application.cfm.
To be specific:
<cfapplication name="testname" sessionmanagement="Yes"
loginStorage="session" CLIENTMANAGEMENT="YES"
SESSIONTIMEOUT=#CreateTimeSpan(0,0,30,0)#>
So far I have tried following the CFApplication.html from Adobe (https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-a-b/cfapplication.html) to fix this, but have not had any luck. Any assistance or guidance is appreciated in fixing this matter. Thank you in advance!
Do you have access to the ColdFusion administrator for these sites? In the Server Settings-->Memory Variable section are universal settings for the session cookies: HTTPOnly and Secure Only. Make sure those are turned on.
In addition, do the sites use the CFCOOKIE tag. Make sure those tags are setting the 'secure' and 'httponly' attributes to TRUE.
Last, are the sites declaring COOKIE scoped vars in any CFPARAM tags/calls? If so, those will set cookies and are not secure and there is no setting I've found to make them so.

Coldfusion 9 cfscript cfcookie and cookie (script style)

I am trying to set my cookie CFIDE and CFTOKEN to be HTTPOnly in Coldfusion 9...
Here is what I have tried (didn't error but didn't work):
cookie.CFID = "#session.cfid#,httpOnly='true'";
cookie.CFTOKEN = "#session.cftoken#,httpOnly='true'";
I also tried (no go...and no error):
cookie.CFID = "#session.cfid#;httpOnly='true'";
cookie.CFTOKEN = "#session.cftoken#;httpOnly='true'";
And this (which I think only works in CF10):
cookie.CFID = {value="#session.cfid#", httpOnly="true"};
cookie.CFTOKEN = {value="#session.cftoken#", httpOnly="true"};
Then this (didn't error but didn't work):
cookie( name="CFID" value="#session.cfid#" httpOnly="true" );
cookie( name="CFTOKEN" value="#session.cftoken#" httpOnly="true" );
When I run these I do a empty cache hard reload in Chrome. When the page reloads I should see the Resources Cookies HTTPOnly column show check boxes.
I'm probably exhausted and could have hit the right combo of things above and I got a false positive on failure from jumping around too much. Sometimes cached things get the best of me.
I have the CFML container style that works but my Application.cfc is all script style and I want to keep it that way...So how do I do this script style in Coldfusion 9?
Update for my fix:
I used the getPageContex() below, but it didn't work as it was. Also onSessionStart() event handler changed to create the session.CFID and session.CFTOKEN with the CreateUUID() which is also new in my Application.cfc file. So for posterity here is what that block of code looks like.
function onSessionStart(){
getPageContext().getResponse().addHeader("Set-Cookie", "CFID=#session.CFID#;path=/;HTTPOnly");
getPageContext().getResponse().addHeader("Set-Cookie", "CFTOKEN=#session.CFTOKEN#;path=/;HTTPOnly");
}
Another Note: For some reason if the session is cleared and the onsessionstart() handler is requested this set cookie stuff above will fail. There has to be a try catch block or exception handling of some sort added to account for a reload problem. The best thing is to upgrade to a patched up release of Coldfusion 10 (or soon to be released CF 11).
You can use the PageContext object to set cookies in cfscript:
getPageContext().getResponse().addHeader("Set-Cookie", "CFID=#session.CFID#;path=/;HTTPOnly");
getPageContext().getResponse().addHeader("Set-Cookie", "CFTOKEN=#session.CFTOKEN#;path=/;HTTPOnly");
For session cookies, there's an easier way.
Enabling server-wide HttpOnly session cookies
The ColdFusion 9.0.1 update added a server-wide setting to add the
httponly attribute to all session cookies created by ColdFusion (such
as the CFID and CFTOKEN cookies, or the JSESSIONID cookie on JRun). To
enable this setting, if you are running a JRun J2EE installation or
multi-server installation, you must edit jvm.config, otherwise you can
enable this setting from the CF Administrator. If you are running a
J2EE server other than JRun consult your documentation for an
appropriate setting. J2EE servers that support the Servlet 3.0
specification can specify
true
in the /WEB-INF/web.xml file.
http://www.adobe.com/devnet/coldfusion/articles/coldfusion-securing-apps.html
You can use this code in your application.cfc inside of the onsessionstart function.
<cfcookie name="CFID" value="#session.cfid#" httponly="true">
<cfcookie name="CFTOKEN" value="#session.cftoken#" httponly="true">
There is no way of setting this inside of cfscripts. cfcookie is not supported in script form in cf9. There are flags in the application settings added to CF10 to address this issue, however, CF11 will have full support for it inside of scripts. Unfortunately, I think you will have to forego the uniform code for functionality. Unless you have access to your CFIDE/Administrator. You can add a java argument to turn it on server wide. Add this to your JVM config
-Dcoldfusion.sessioncookie.httponly=true
All of this is detailed here http://www.petefreitag.com/item/764.cfm

ColdFusion 10 not writing to cfcookie on same browser but different computers

I am migrating websites from a server using CF 8 to a new one using CF 10. In this one site, I have a query that looks up talent and then writes the resulting list to a cfcookie. On my computer with any browser it works correctly. My client uses the same browser as I normally use (Safari) and his browser is not updating the cfcookie with the new talent list after a search. They are very unhappy making me unhappy also. Any ideas as to what might be causing this problem.
In the application.cfm (yes, I know I should be updating to cfc but not enough hours in the day):
<CFAPPLICATION NAME="lil"
CLIENTMANAGEMENT="yes"
SESSIONMANAGEMENT="yes"
SESSIONTIMEOUT=" #createTimeSpan(0,0,30,0)#"
APPLICATIONTIMEOUT=" #createTimeSpan(0,1,0,0)#"
clientstorage="cookie">
Setting the cfcookie:
<cfif isdefined('getTalent.recordcount') and getTalent.recordcount gt 0>
<cfcookie name="tSearch" value="#valueList(getTalent.talentID)#" httponly="true" expires="1">
</cfif>
How large is the amount of data you are storing in the cookie, and could the client be storing more than you are? Are they possibly using a cookie-blocking security app of some kind?
In a bigger-picture kind of mindset, if the user is doing a search and getting results, rather than storing the results in a cookie, why not use either a session-scoped variable, or simply use the CF identity cookies already in place to store their results in a temporary database location? Cookie issues can be harder to track down, but unless you're not managing sessions in your Application.cfc or cfapplication tag, each user is already getting a unique ID which you can leverage server-side for this type of thing.
One last thought... are you doing any sort of CFLOCATION redirect, after attempting to store the cookie? Redirecting can cause CFCOOKIE commands to not be honored, because in essence the user's browser is redirected before it receives the response.

Coldfusion load session from Id

Is there any way to load a specific user session by providing the correct value of CFTOKEN and/or CFID?
Something like php's session_id($id) function.
Or some way to change data of an specific session.
I need a webservice that will add or change some information on a specific user session. I know the CFID and CFTOKEN values because I share a subdomain cookie. However applications are on different servers
Not that it's the best way of doing things, as it uses undocumented code that can change without notice between versions. But you can use certain methods to access sessions.
<cfscript>
appName = 'zadsApp';
jSessTracker = CreateObject('java', 'coldfusion.runtime.SessionTracker');
appSessions = jSessTracker.getSessionCollection(JavaCast('string', appName));
targetSession = appSessions[appName & '_' & sessionCFID & '_' & sessionCFTOKEN];
// Dumping, reading, writing WILL update the last accessed time.
// There are ways around this if needed...
WriteDump(targetSession);
targetSession.something = 'A new value';
</cfscript>
Now you mention that this is on a different server, can I just double check that you want a seperate server to change a session on another server? Without putting any kind of code like the above on that server (the one with the session)? Although it'd be a heck of a lot easier if the code was on the same server, you might be able to perform code like this remotely using JMX... but I'm sure there must be an easier way to do all of this.
You can do it by passing the correct values on the URL, more information available here
http://ruthsarian.wordpress.com/2005/10/03/cf-session-hijacking/
ColdFusion uses two unique values to keep track of user session
information. These values are CFID and CFTOKEN. They are stored as
cookies but can also be passed along the URL and inside POST data.
Session variables are a place to store information specific to the
user and to the current session (such as whether or not a user is
logged in).
It is possible to hijack a user’s session by supplying the correct
CFID and CFTOKEN values to the server, either on the URL, or wherever
else you want.
What it sounds like you are trying to do is effecitvely described by this post http://old.nabble.com/ColdFusion-9-Session-Replication-td32621620.html which advises against session replication on grounds of high network usage due to it.
Where you are trying to maintain a specific sessions scope across multiple physical servers. The way I've worked around this in the past is to maintain a database storing the information which needs to be passed between physical servers tied to a UUID. For this purpose you could just use the CFID/CFTOKEN values as your database PK's, or you could make another PK altogether. This would then allow you to pass the CFID etc on the URL string, and then if it hits a server which it hasn't so far hit (i.e. no session / session wasn't loaded using those CFID/CFTOKEN) then you can load the variables you need from a database.
Edit an alternative non-database method
Firstly set up a script on one server i.e. getSessionData.cfm which returns
the data in the session scope in transportable format i.e. using
SaveObject() (if on CF9), or maybe SerializeJSON(), something like
that
<!--- on source server, getSessionData.cfm --->
<cfscript>
WriteOutput(ToBase64(ObjectSave(session)));
</cfscript>
Then set up a handler that will request data from the other server
using a cfhttp request populating CFID/CFTOKEN to access the session, and then pull that data into the session on the new server.
<!--- on target server --->
<cfhttp url="http://sourceserver/getSessionData.cfm">
<!--- Params to pass through CFID/CFTOKEN or any other cookie/url/post params etc --->
</cfhttp>
<cfscript>
structToImportToSession = ObjectLoad(ToBinary(cfhttp.FileContent));
for (thisStructKey in structToImportToSession) {
session[thisStructKey] = structToImportToSession[thisStructKey];
}
</cfscript>
The problem with this is that I would feel uneasy with this kind of script being on my server in a production environment. It also means that you will need to know explicitly which physical server the user came from so that you can request the getSessionData.cfm script from the correct server.
This post from Ben Nadel seems to employ a similar principle to update session data, same could be applied for updating it I expect, http://www.bennadel.com/blog/725-Maintaining-Sessions-Across-Multiple-ColdFusion-CFHttp-Requests.htm
Personally I'd still advise the database-drive method as it gives you clearer mechanics by which to purge old sessions etc, however this second option should be viable and give you access to what you need.
as long as the session isn't expired you can access a session by using the CFID and CFTOKEN in the url

Coldfusion uses wrong (cached?) variables at random

We have a dedicated server running CentOS and Coldfusion 8.
All cfmail email is routed through Google with cfmail and smtp.
Every now and then, when cfmail is used, the 'FROM' field uses an address from a totally different website.
For instance:
Use form on Site A
Get an email: "Subject: On Site A From: siteb#siteb.com"
Where the from is a completely different variable in another set of code on another part of the server- there is no reason it should see this.
On the other side, sometimes sending an email to sitea#sitea.com has email wind up in Site B inbox, a completely different Google account.
What causes this to happen? Some kind of memory/cache issue? Or is there a funky DNS record causing issue?
Example:
Application.cfm (starts with some UDF includes, and then):
<cfinvoke component="#request.componentPath#.variables" method="getGlobal" />
Variables.cfc (a lot of variables defined within, but here is the cfmail vars):
<cffunction name="getGlobal" access="public" output="false" returntype="void">
<cfscript>
request.siteEmail = "email#mysite.com";
request.siteMailServer = "smtp.gmail.com";
request.siteMailUsername = "root#mysite.com";
request.siteMailPassword = "[redacted]";
</cfscript>
</cffunction>
It sounds like it's possible it could be a var scoping issue, but we can't know for sure until you share some code...
Looks like you're running multiple sites? there's a setting in the CF caching page in admin to do with caching web server paths:
From http://help.adobe.com/en_US/ColdFusion/9.0/Admin/WSc3ff6d0ea77859461172e0811cbf3638e6-7ffc.html :
Disabling the cacheRealPath attribute To ensure that ColdFusion always returns pages from the correct server, disable Cache Web Server Paths in the Caching page of the ColdFusion Administrator. (When you use the multiserver configuration, set the cacheRealPath attribute to false for the ProxyService in the jrun_root/servers/servername/SERVER-INF/jrun.xml file.)
Might not be it, but it's at least quick to try out.