ChocolateChipCookiesIn a recent post, CodingHorror blogged about a story of one of his friends attempts at writing his own HTML sanitizer for his website.

I won't bother repeating the details but it all boils down to the fact that his friend noticed users were logged into his website as him and hacking away with admin access.  How did this happen?  It turned out to be a Cross Site Scripting attack (XSS) that found it's way around his HTML sanitizing routines.  A user posted some content that included mangled JavaScript that made an external reference including all history and cookies of the current users session to an alternate machine.

CodingHorror recommended adding the HttpOnly attribute to Set-Cookie response headers to help protect these cookies from being able to make their way out to remote machines.  Per his blog post:

  • HttpOnly restricts all access to document.cookie in IE7, Firefox 3, and Opera 9.5 (unsure about Safari)
  • HttpOnly removes cookie information from the response headers in XMLHttpObject.getAllResponseHeaders() in IE7. It should do the same thing in Firefox, but it doesn't, because there's a bug.
  • XMLHttpObjects may only be submitted to the domain they originated from, so there is no cross-domain posting of the cookies.

Whenever I hear about modifications made to backend servers, alarms start going off in my head and I get to thinking about how this can be accomplished on the network transparently.  Well, if you happen to have a BIG-IP, then it's quite easy.  A simple iRule can be constructed that will check all the response cookies and if they do not already have the HttpOnly attribute, then add it.  I went one step further and added a check for the "Secure" attribute and added that one in as well for good measure.

when HTTP_RESPONSE {
  foreach cookie [HTTP::cookie names]
  {
    set value [HTTP::cookie value $cookie];
    if { "" != $value }
    {
      set testvalue [string tolower $value]
      set valuelen [string length $value]
      #log local0. "Cookie found: $cookie = $value";
      switch -glob $testvalue {
        "*;secure*" -
        "*; secure*" { }
        default { set value "$value; Secure"; }
      }
      switch -glob $testvalue {
        "*;httponly*" -
        "*; httponly*" { }
        default { set value "$value; HttpOnly"; }
      }
      if { [string length $value] > $valuelen} {
        #log local0. "Replacing cookie $cookie with $value"
        HTTP::cookie value $cookie "${value}"
      }
    }
  }
}

If you are only concerned with the Secure attribute, then you can always use the "HTTP::cookie secure" command but as far as I can tell it won't include the HttpOnly attribute.

So, if you determine that HttpOnly cookies are the way you want to go, you could manually configure these on all of your applications on your backend servers.  Or... you could configure it in one place on the network.  I think I prefer the second option.

-Joe