This is a continuation of a topic that I have been blogging about and thinking about for a long time. Session management and cookie security are really interesting topics that I could yammer on about for hours. Go ahead, ask my wife.
The behavior is that if the ColdFusion server is presented with a cookie that contains a session token that was ever valid (since last server restart), ColdFusion will reuse that token to create a new session.
ColdFusion is not going to reinflate the session with any old data, so we do not need to worry about any information leakage there. It actually seems to create a new empty session, and so at first I wasn't sure why it bothered me. If a token became compromised, a hacker could populate their browser with it, then go to the site and get a new session. So what?
Then it occurred to me what the vulnerability was. And I think my instinctive reaction was correct.
The VulnerabilityIf you keep using the same session token with your application, and that token becomes compromised, then your session can get hijacked anytime between when you log into the application and when your session times out. Any of your sessions. Ever. As long as you're using that same token.
If I am a hacker, and I have compromised your session token (by whatever means: XSS, social engineering, packet sniffing), then I can create a script that will hit the site that is being hacked ever N minutes with that token, then just leave that for a few days.
Every time I hit the site with the compromised token, it will either create a new session or persist an existing session. Eventually, you will log onto the site again. After that, every time my script hits the site it will persist your session, then I can, at my leisure, go back to the site with your valid, and active, session and impersonate you.
It's kind of confusing to think about. I hope my explanation is clear enough (but I doubt it).
So what can we do about this vulnerability?The way to mitigate the risk of this vulnerability is to rotate session tokens. Every time you start a new session, it should be started with a new session token. This is easier said than done. You cannot simply ask CF for a new token. Cookies need to be replaced, which requires multiple HTTP messages.
The way I am proposing to solve this problem is experimental. I've thought long and hard about this one and this is what I have come up with. I have not implemented this anywhere, and I have not done a ton of testing with it. I would love to get opinions on this, I am not sure it is a great solution, or even a good one.
this.sessionManagement = true;
this.sessionTImeout = createTimespan(0,0,0,30);
this.setClientCookies = false;
<cffunction name="onSessionStart" access="public" output="false">
<cfif NOT StructKeyExists(URL, "sessionInitialized")>
<cfcookie name="CFID" value="" expires="now" />
<cfcookie name="CFTOKEN" value="" expires="now" />
<cflocation url="#CGI.script_name#?sessionInitialized" addtoken="false" />
<cfcookie name="CFID" value="#session.CFID#" />
<cfcookie name="CFTOKEN" value="#session.CFTOKEN#" />
In this Application.cfc I have first told ColdFusion not to set the token cookies (this.setClientCookie=false). I will take care of that. Then, in my onSessionStart() method I check to see if a sessionInitialized URL parameter was sent. If the sessionInitialized parameter does not exist, then I know that I have not explicitly reset the cookies yet, so I use the <cfcookie> tag to expire the CFID and CFTOKEN cookies that might be passed. Then the method redirects the user back to the same page they just requested, this time with no session cookies but with the sessionInitialized parameter.
When the redirected request hits the application, onSessionStart() will be fired again, because no valid session cookies will be presented to it. This time, since the sessionInitialized parameter will be present in the URL string, I will not expire the cookies, instead I create new session token cookies with the new CFID and CFToken that CF has created. Now that a valid session with valid session token cookies have been created, onSessionStart() should not run again, so we should not need to worry about adverse effects from that happening.
Life I said, I am not sure if this it the best solution, but I cannot think of another way to rotate the session tokens effectively.
The one downside to this method, and maybe someone can help me figure out how to address this, is that it is very difficult to detect if the user has cookies disabled so that I can give them a proper warning that they must have cookies enabled for the application to work.
As with all session management issues in ColdFusion, we also need to worry about how this will work with JEE sessions. We do not have as much control over the JSESSIONID cookie as we do with the CFID and CFToken cookies. I've tried it out with JSESSION tokens and it seems to work OK, but I have not done much testing with it.