Setting HTTPOnly and Secure for the ColdFusion Session cookies

Many of you probably know that I sell UI Flex Components under the name of Flextras. Part of the decision I made when starting the company is to open up a merchant account and process credit cards on the site, instead of using a third party site such as PayPal. This gives us complete control over the branding experience.

As part of this decision to touch credit card data, the site is subject to routine PCI Compliance scans, and the scan often makes suggestions for items that must change on the site in order to stay compliant. I think the penalty for not changing this stuff is immediate death.

The latest scan failed me for a few issues that have been on the site since it launched. If it was fine for the first 18 months, why do I have to spend and money changing it now? But, I digress. I wanted to write about one of the things they are making me change this time around

The two issues are these:

  1. Cookies set by the site are not set to HTTPOnly cookies.
  2. When cookies are served over HTTPS they are not specified as secure cookies.

The scan information was very light, so I'm not sure which cookies they are referring to. The site's code doesn't set any cookies, however there are some tracking cookies set by analytic software and session tracking cookies set by ColdFusion.

So, the question is, how do I Set the ColdFusion session cookies (CFID and CFToken) to be HTTPOnly and Secure? A quick google search brings up these two Stack Overflow questions, which lead to this post by Jason Dean. Thank you Jason!

Jason explains how to modify the JSessionID to set the HTTPOnly and Secure properties on the cookie. I was easily able to encapsulate Jason's code into a method, which I put in Application.cfc:

<cffunction name="recreateSessionCookies" returntype="void" output="false">
Do some cookie Magic to make cookies be HTTPOnly

<!--- Expire the old Cookie --->
<cfcookie name="cfid" expires="now"/>
<cfcookie name="cftoken" expires="now"/>

<!--- Get the HTTP Response Object --->
<cfset response = getPageContext().getResponse() />

<!--- Set the specifics for the cookie --->
<cfset path = "/" />
<cfset domain = '' />
<cfif cgi.HTTPS is "on">
<cfset secure = "Secure" /> <!--- Use val of "Secure" or leave blank --->
<cfset secure = "" /> <!--- Use val of "Secure" or leave blank --->

<cfset HTTPOnly = "HTTPOnly" /> <!--- Use val of "HTTPOnly" or leave blank --->

header = "cfid" & "=" & session.cfid & ";domain=." & domain & ";path=" & path & ";" & secure & ";" & HTTPOnly;
response.addHeader("Set-Cookie", header);
header = "cftoken" & "=" & session.cftoken & ";domain=." & domain & ";path=" & path & ";" & secure & ";" & HTTPOnly;
response.addHeader("Set-Cookie", header);

Basically, the code expires the current cookies, and re-creates then using the same values. Along the way it specifies the HTTPOnly and Secure header. I call this method in OnSessionStart of the Application.cfc:

<cfset recreateSessionCookies()>

HTTPOnly works great. But, Secure has given me a bit of a head scratcher. If you set the secure value on a cookie, without using HTTPS the session is created new each time which defeats the purpose.

Ideally, I want to turn the secure setting on and off as people switch from secure to non-secure portions of the site, keeping the same same session users surf the site. ( This doesn't quite work as I had hoped, but more on that later ).

I create a session variable in onSessionStart, named previousURLSecure:

<cfset session.previousURLSecure = cgi.https>

This defaults the value. Now, in OnRequestStart I can previousURLSecure against cgi.https . If they have changed, that means that the site surfers have moved from secure to non-secure, or non-secure to secure and we need to swap the secure attribute of the cookie. This is the code in onRequestStart:

<cfif (session.previousURLSecure NEQ cgi.HTTPS)>
    <cfset this.recreateSessionCookies()>
<cfset session.previousURLSecure = cgi.HTTPS>

It's a quick check, and if things have changed it calls the recreateSessionCookies method. It also saves the HTTPS state of the current URL.

This code is live on the Flextras site right now. So, go over and add something to your cart (non-secure), then sign in (secure). You should see the item in your cart.

The go to the address bar of your browser and change 'http' to 'https'. The items in your cart will vanish and your login go away. This does not happen if you never use the secure attribute when creating, or modifying, the cookies.

So my conclusion is that you can easily go from non-secure to secure cookies, but you can't go the reverse. If you use non-secure cookies they'll work for both HTTP and HTTPS. But, secure cookies are not accessible via HTTP. Am I right?

I'm thinking this may be expected behavior for security purposes to prevent some form of session hijacking or other hack attacks. IS it?

I thought of a few hacks, such as storing a copy of the session ID in an alternate cookie, and using that to reset CFID/CFToken. But, I doubt that will be acceptable from a PCI Compliance standpoint.

I'm worried that not even this approach will be acceptable to the PCI Compliance scanner. If not, I'll have to move the whole site to HTTPS; which may suck, especially for file downloads.

So, has anyone out there had any experience with this sort of thing? Got any suggestions for me?

If you can help, I have some "Friend and Family" discount passes to Flex Camp Wall Street coming up next week.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Sam Farmer's Gravatar Which version of ColdFusion are you running? On ColdFusion 9 the cookie tag has both httpOnly and secure attributes.
# Posted By Sam Farmer | 11/10/10 1:57 PM
Jeffry Houser's Gravatar Running CF8 in production.

I guess those attributes would make things a bit easier in terms of code I had to write. But, wouldn't solve the issue of preserving the session when switching between https and http.
# Posted By Jeffry Houser | 11/10/10 2:33 PM
JAlpino's Gravatar Instead of using a non-secured cookie to transmit back the session info (which pci would definitely complain about), how about passing the identifiers or a key to those identifiers from secured to non-secured resources explicitly via the url string? I would definitely encrypt those values before hand, perhaps something like the following:

<cfset bridgeIndentifiers = encrypt("cfid=#session.cfid#&cftoken=#session.cftoken#", yourkey, yourAlgo) >


<a href=" to non-secure page</a>

Then in onRequestStart method in your Application.cfc, look for the "_bridge" query string param, decrypt and use those values to re-write the session cookies.

I can't say that I've personally used this approach (I haven't had the need) but understanding what the issue is, I think it could work and get you to "pass" the compliance scan...
# Posted By JAlpino | 11/10/10 4:47 PM
Jeffry Houser's Gravatar @JAlpino

I like that idea a lot. I'll have to see if it applies. I don't think there is any place on the site where we explicitly link from secure back to non-secure. I guess it is more of a theoretical thing I noticed.
# Posted By Jeffry Houser | 11/16/10 10:13 PM
Floyd's Gravatar "So my conclusion is that you can easily go from non-secure to secure cookies, but you can't go the reverse. If you use non-secure cookies they'll work for both HTTP and HTTPS. But, secure cookies are not accessible via HTTP. Am I right? "

You misunderstand the purpose of secure cookies, which is to never let their value be transmitted plaintext.

So by "upgrading" a non-secure cookie to secure you are undermining the purpose of the secure flag, since the cookie value has, until this point, been transmitted plaintext.

The wikipedia article on cookies in my opinion sufficiently details the intended use of secure cookies. From what I read here you are misusing them and are opening the door for your site's visitors to have their secure sessions hijacked.
# Posted By Floyd | 11/24/10 11:27 AM
Jeffry Houser's Gravatar Floyd,

That seems like a pretty valid concern. I'll probably just end up pushing the whole site to HTTPS except for downloads which I'll revert back to HTTP.
# Posted By Jeffry Houser | 11/30/10 3:08 PM
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version

pure garcinia cambogia

payday loans online

seo services

seo services