mmmmMMmmmmmmm Cookies (part 2) - Security Series #12.1
This post is a day later than I had hoped. Oh well, what can you do.
In my last post we started talking about cookie security. There is a LOT to cookie security and we only touched the surface. We are going to continue today by talking about session token cookies, SSL, and the SECURE flag.
Session Token Cookies
Session Token Cookies are used to store the browser's session token so that when the browser contacts the web server that it knows which session belongs to that browser. Because of the stateless nature of the World Wide Web, this is necessary to persist data between web requests.To read more about session management and session tokens check out some of my previous posts.
Session Security in ColdFusion
Session Tokens in ColdFusion
Is important to know, that your users' sessions tokens are HIGHLY sensitive information. If session tokens become compromised, then session hijacking is easy for anyone that obtains a valid token. This is why it is important to make sure our session token cookies are secure.
SSL and Cookie Security
One of the problems with cookies is that everything is done "in the clear". Cookies are simple text and numeric values and these values are sent in clear text which can be easily intercepted, unless SSL is used.When a secure connection is made between a client and a server, then all the information sent between those two machines is encrypted, including the cookie values. This, of course, is great for security, since the encrypted session token cannot be intercepted and used for a session hijacking.
Let me just give you a quick example to try to scare you. You have a client with a very simple request. She wants a blog. You say "No Problem!", because, of course, thanks to our awesome community, there are several blog options from which to choose. You choose one and set it up. You think to yourself, "Does this site need SSL?", and decide it does not. It's just a simple blog, the only users, besides the administrator that will be accessing it, are all anonymous and so you don't need to worry about having those users' sessions hijacked.
But wait. What about your administrator? Your blogger? Isn't she a user? What happens when she sits down at the local coffee shop with her laptop and hits that wireless access point called "Free Public Wifi" and goes to log into her blogging site. Well, because she is not connected via SSL, everyone one of her page requests will be broadcasting her highly sensitive session token cookie "in the clear". If some malicious little punk was sitting there, monitoring network traffic, and saw that, he could easily grab that cookie, duplicate it on his machine, and browse to the blogging site himself. He would be instantly logged on as your client and could vandalize to his heart's content.
A few hours later you would get a call from an angry client wanting to know how the site you set up for her got hacked. Your reputation takes a hit and you get to clean it up for free.
The moral of this story is a simple one. It is also one that nobody wants to hear. But I don't care what you want to hear, I just want to give it to you straight.
If you are using session management and not using SSL, then your site is not secure. Period.
The SECURE flag
Cookies have a pretty cool feature that can help protect you from yourself and from your clients. It is the SECURE flag. When a cookie has the SECURE flag set to "true", then the cookie will not be sent to the server on anything except an encrypted connection. Pretty cool, huh?So how do we set the SECURE Flag?
Great question. Unfortunately, this is one of those areas where ColdFusion drops the ball a bit. There are several ways to protect your session token cookies that ColdFusion does not allow you to do without jumping through a few hoops. This is one of them. There is no way (to my knowledge) to tell ColdFusion to write session tokens with the SECURE flag set to "true". So we need to write the cookies ourselves.The first thing we need to do is tell ColdFusion NOT to write the session cookies. We do this in our Application.cfc (or Application.cfm if you are kickin' it oldSkool).
In the pseudo-constructor area of Application.cfc (which is the area right below the <cfcomponent> tag and right before the first function) put:
<cfset this.setClientCookies = false />
In Application.cfm add the setClientCookies attribute to the <cfapplication> tag and set it to "false".
This will tell ColdFusion not to write the session token cookies.
Next we need to write the cookies. So in Application.cfc in your onSessionStart() method, or in Application.cfm where ever you handle your session variables, add:
<cfheader name="Set-Cookie" value="CFID=#session.CFID#;secure=true;" />
<cfheader name="Set-Cookie" value="CFTOKEN=#session.CFTOKEN#;secure=true;" />
I have tried this with jsessionid and it does not seem to work. If anyone has an experience with making the jsessionid token cookie secure, I would love to learn about it.






http://www.jalpino.com/new/index.cfm/event/read/en...
Thanks for the comment. I saw your post when I was doing my research and testing. I forgot to mention it, but there is a reason I chose to use <cfheader> instead of <cfcookie> and that reason is the HTTPOnly flag cannot be set with <cfcookie>. So by using cfheader, you can set both SECURE and HTTPOnly.
It is interesting that you can use cfcookie for jsessionid but that cheader would not work. I will need to look into that.
BTW, nice series, very informative and relevant. I'm noticing that many of my company's clients are becoming more aware of the security aspects of applications they use, on a much deeper level than they inquired about before in the past. Over the past year or so, we've been subject to several large security questionnaires and requests for independent application scans. The information that you are posting is great and definitely helpful!
Again, thanks for reading. It's comments like these that inspire me to keep going.
Invaluable. Thank you.
Glad to see another MN developer leading the secure development charge!
I was wondering a couple of things.... In your code - is this code correct? <code>
<cfheader name="Set-Cookie" value="CFID=#session.CFIF#;secure=true;" />
<cfheader name="Set-Cookie" value="CFTOKEN=#session.CFTOKEN#;secure=true;" />
Should the session.CFIF be CFID?
Either way: Why are you setting the cfid and cftoken cookie to the exact same values as the session.cfid and cftoken? I thought we were trying to get around the easily guessed values in those default values.
Also - Why are you setting the secure=true in the application or session settings? Most user auth systems don't actually secure themselves until you attempt to login in somewhere - so the user is often well beyond the session Start or the Application Start at that point. How do we know for sure the user is using ssl when they start up?
I hope I am not being too confusing to you b/c I am throwing myself for a huge loop.
thanks,
Chris
Yes, I had CFIF where I wanted CFID. That is now fixed. Thanks.
Now, I am setting the cookies to the same value that is in the session scope because that is what ColdFusion is expecting to use to find that user's session data, if I try to change it to anything else, then I will lose the session.
The way to get rid of the weak value for CFToken is to check the "Use UUID for cftoken " setting in the ColdFusion administrator. This will stop ColdFusion from using stupid 8 digit numbers for the CFToken and use a 35 character UUID instead. Nice. There is nothing we can do about the CFID. It is fine the way it is. As long as the CFToken is hard to guess.
You last question is a good one. In my example, the assumption I am making is that the application is on SSL from the very beginning and that any attempt to browse to the site with HTTPS will result in a re-routing.
If, as you suggest, your site does not switch to SSL until a login, then you would want to change your cookies at that point instead of in the onSessionStart() method. Technically, you would want to invalidate that old session completely and start a new one with the SECURE setting, but that is a future post that I will explain in more detail later. Great observation. Thanks!
Now that I am re-reading the post and the comments I am not sure about this: Why is it that we are setting these cookies at all if we have turned setClientCookies to false? Client cookies are off - so won't these cookies not even get used? I think I am still really misguided as to the diff between session tokens and session cookies.
As for why yours is not using UUID cookies, I am not sure. It should not require restarting ColdFusion. But try it anyway. Also, delete any existing cookies you have. If that does not work, email me at jason@12robots.com and we'll set up a connect session and try to figure it out.
First of all, thanks guys. Secondly, I think I have synthesized your strategies to provide a solution for JSESSIONID.
1. In Application.cfm (yes, oldSkool), I specified setclientcookies="false" to ensure that CFID and CFTOKEN were nowhere to be seen.
2. Along with JSESSIONID, I get a client-side cookie var called CFAUTHORIZATION_myApp. I'm not sure what this is (any help?), but it seems to go along with JSESSIONID. It needs to be preserved, as JSESSIONID does, to keep the session going. So I treat is as JSESSIONID
3. Here's the code:
<!--- save current JSESSIONID and CFAUTH locally --->
<cfset currJSessionID = cookie.JSESSIONID>
<cfset currCFAuthorization = cookie.CFAUTHORIZATION_myApp>
<!--- clear cookies --->
<cfset tmp = StructClear(cookie)>
<!--- redeclare cookies w/cfheader tag so that we can set them as HTTPOnly -->
<cfheader name="Set-Cookie" value="JSESSIONID=;domain=#CGI.SERVER_NAME#;path=/;HTTPOnly" />
<cfheader name="Set-Cookie" value="CFAUTHORIZATION_myApp=;domain=#CGI.SERVER_NAME#;path=/;HTTPOnly" />
<!--- assign stored values with cfcookie tag so that we can set security --->
<cfcookie name="JSESSIONID" value="#currJSessionID#" secure="true">
<cfcookie name="CFAUTHORIZATION_myApp" value="#currCFAuthorization#" secure="true">
Admittedly you could code this a little tighter but it's 4:30am. Also note it's a dev server so domain is set to an IP.
The key thing turned out to be the path. If you do not assign "path=/" explicitly, ColdFusion assumes that you are declaring a new cookie that just happens to be *named* JSESSIONID instead of a JSESSIONID that will hold sessions across your application.
Also, my site doesn't have SSL, so when I do the above code, it kicks me off immediately. I have to set secure="false" to work with my app. But this fits with what JAlpino said about needing SSL to handle secure cookies, so I am comfortable with the code until I get my SSL.
I want to thank you guys personally for helping me with this!
(I am a security n00b, my main job in life is author of young adult novels, I do this for money on the side)
So I have tried your code in every way I can think of, and consistently, I get the same result that I did with any of my methods. When I try to set the JSESSSIONID cookie, with DOMAIN, PATH, or HTTPOnly, I either get a duplicate cookie, or it just doesn't work.
The <cfcookie> tag does work to make the jsessionid SECURE, but it is not HTTPOnly from the <cfheader>
The other issue I come across is that ColdFusion (or maybe it is JRun) will not let you create a J2EE session cookie with any path other than "/". Once you try to set a path to any kind of sub-directory, it creates a duplicate cookie.
Please let me know if you actually are getting different results. But as far as I know, if you use a <cfheader> to right a cookie, and then follow it with a <cfcookie>, the <cfcookie> will overwrite the cookie, not append information to it.
Thanks!
<cfif IsDefined("cookie.JSESSIONID")>
<cfheader name="Set-Cookie" value="JSESSIONID=#cookie.JSESSIONID#;domain=#CGI.SERVER_NAME#;path=/;HTTPOnly" />
</cfif>
Firebug says that my JSESSIONID is HttpOnly all the way through--*except* when I log out and clear my cookies. Thoughts?
the CFAUTHORIZATION_myApp cookie is set by the <cfloginuser> tag. It tracks user authentication.
You can get rid of it by specifying a session storage for the login (just set the "LoginStorage" application variable to "session").
I switched to session storage because I had issues with session timeout: the session was timing out before the cfauthorization cookie, leading to odd behaviours (the user being considered logged in but with an empty session).
I'm also trying to secure the jsessionid, I would like to specify a path more specific than / (many applications being behind a proxy at my job, they are overwriting each others sessions and leaving too much place for a malicious application). Let me know if you found anything on this...
Thanks for this interesting blog!
As to making JSESSIONID "secure", I don't know if that is possible yet (jalpino definitely has a solution for making CFID and CFTOKEN secure) but I haven't implemented SSL yet, I am still developing.
Thanks!
http://tinyurl.com/12RobotsjSessionCookies
I'd expect HTTPOnly to be an option for the cfcookie tag in CF9 or, at least, to be added by the OpenCFML advisory committee. Until then, there's one other option I haven't seen mentioned. Understandably so, but still. Most of the major java servlet engines now have the option to force cookies to be HTTPOnly by default. Tomcat, Resin, and Jetty all have this and it's usually a case of adding one line to the XML config file at the context level. I know many people are on JRun or are hosted and might not have that type of control, but for those of us running our own server or with flexible hosts, it's something to consider.
Thanks for the comment. I just have a few comments/questions.
1. I'm not sure where you are seeing a "workaround for redirection" in any of the suggested solutions that use cfheader.
2. If you are setting an encrypted value to a cookie, it should be encoded as a string (BASE64 or Hex or something), I don't see how that could fail where any other string would work.
3. I'm not sure what to expect for CF9 as far as cfcookie is concerned, but there are plenty of people that will not be immediately upgrading that this still merits research and concern.
4. I'd love to see a HOW-TO on setting HTTPOnly or SECURE flags for J2EE session tokens in any of the servlet containers. I'll admit that I have not looked very hard for such docs, but if you know of any, please link me.
Again, thanks for the comments.
2. Absolutely correct. Base64 encoding resolved it.
3. Fair enough. Still might be useful for those who can take advantage of it.
4. Tomcat
http://stackoverflow.com/questions/33412/how-do-yo...
Resin
http://ccl.pku.edu.cn:8080/resin-doc/doc/webapp-ta...
I've got Tomcat runnning with httponly session cookies now.
Thanks for following up.
1. I know it seems kludgey, but I am not sure there is a better solution. Rotating session ids required a round trip HTTP request to get and set the new cookies. So I am not sure of a better way. Can you point to an example of a way another language does it? That might help us figure out a better way or suggest a better way to Adobe.
2. Glad to hear it.
4. Thanks for the links. I am going to try that out. I got some info from someone else I am going to try out too.
@micheal thanks for posting the links on enabling httpOnly at the server level for resin and tomcat. I looked for info on configuring jrun but could not find any. I wonder if "standard" installs of CF are left to programmatic solutions.
Put this after the </persistence-config> element.
<cookie-config>
<cookie-secure>true</cookie-secure>
</cookie-config>
This answer cost us $500 after speaking to Adobe Tech Support. It turns out that this is documented on http://livedocs.adobe.com/jrun/4/Programmers_Guide...
This page also has a lot of other useful JRun info.
http://www.12robots.com/index.cfm/2009/5/6/Making-...
That solution will probably work for a lot of people, but unfortunately, it cannot work for everyone. That solution will only work in an application that is 100% SSL.
Many applications will only switch over to SSL when data needs to be protected, but then switch back to standard HTTP for routine stuff.
If the 100% solution works for you, then that is awesome. It actually works for my applications too. But I know it doesn't work for a lot of developers, which is why I am trying to find a better solution for them.