A Tale of Two Cookies: Securing ColdFusion Session Cookies

Recently at work we went through a security review. It was a great learning experience to have outside contractors try and break into the web application. Found several things that I didn't expect and some others that I had never even considered. One of the last vulnerabilities that they identified was that the CFID and CFTOKEN cookies had an expiration date set too far in the future, 2040 or something like that, and that they did not have the secure flag set.

So I did some research and thanks to a couple of posts by Ben Nadel got a system in place that encrypted/decrypted the cfcookie and expired it immediately. It looked something like this and is nearly identical to his code from the previous articles (all the code goes in the Application.cfc):

      
      
             this.name = "TestApp";
            this.applicationTimeout = createTimeSpan(0,1,0,0);
             this.loginstorage = "session";
             this.sessionmanagement = true;
             this.sessiontimeout = createTimeSpan(0,0,30,0);
             this.setClientCookies = false;
            application.initKey = hash(hash('someRandomChars'));
      
       
         
              
               
               
          
       
      
           
           
       
           
      
      
  

The important parts are the pseudo-constructor that generates the CFID and CFTOKEN cookies with an expiration of "NOW", and the onSessionStart that creates the encrypted session cookie. Because the pseudo-constructor gets executed before anything else the CFID and CFTOKEN are set before they are needed on each page. This allows them to have an expiration of "NOW" so that they never appear in the browser's cookie store, remaining in memory for that page only. This leaves only the encrypted session cookie visible.

While this is a good start, and hides the CFID and CFTOKEN effectively it does not prevent session hijacking. So I went a step further and added to the code to create a unique encryption key for each user, that would make it much more difficult to hijack the session and crack the encryption to access the CFID and CFTOKEN. So here is the expanded code:

    
    
           this.name = "TestApp";
           this.applicationTimeout = createTimeSpan(0,1,0,0);
           this.loginstorage = "session";
           this.sessionmanagement = true;
           this.sessiontimeout = createTimeSpan(0,0,30,0);
           this.setClientCookies = false;
          application.initKey = hash(hash('someRandomChars'));
    
     
         
              
         
              
         
     
    
            
             
             
        
     
    
         
         
     
    
     
    
    
  

With these aims in mind I hit upon the idea to use the cgi.remote_addr as a seed for the encryption key. As it is unlikely that users will change IPs during a their time on the site it provides a good seed that a computer attempting to hijack the session wouldn't have or would have a difficult time trying to acquire. So here is the expanded code:

There are a few extra things going on in the code above. When I was working on this article I discovered these two articles that discuss accessing the original IP in the event that a proxy was being used. Proxies typically add a header named 'X-Forwarded-For' that contains the originating IP address which is what we want to seed with. So I added in a few lines of code to check for the presence of 'X-Forwarded-For' and substitute that for cgi.remote_addr if it is present. While I was at it I added the cgi.http_user_agent as a second seed that helps to make it more difficult to hijack the session.

Does this make it impossible to hijack the session? No. Security is about making it more difficult to gain access. There is always a way to compromise a system, it is just a factor of time and computing power. Of course if you want to introduce more complexity to the algorithm you could repeat the encryption process with different cgi variables acting as seeds to keys ad infinitum.

With that said this code, or something similar, makes sessions much more difficult to hijack and much more secure against hackers then they would be with a plain CFID and CFTOKEN system.

If you enjoyed this article please share it! Also, I have a newsletter that you might enjoy as well. Thanks! -Daniel

Published: 5 Mar 2010 | Tags: code , security , coldfusion