Java and HttpOnly


Nov 6, 2007

HttpOnly is an HTTP cookie property originally developed by Microsoft that makes cookies “non-scriptable” – any attempts to access the cookie value through JavaScript will fail.

HttpOnly mitigates the threat of session hijacking through cross-site scripting, but only partially – more on this later.

Until recently, HttpOnly was only supported in Internet Explorer 6, SP1 and up. Now, however, the latest version of FireFox supports HttpOnly.

It’s easy to specify a cookie as HttpOnly, it raises the bar for an attacker, and it doesn’t affect most regular functionality. So why not set your session identifier cookies to HttpOnly?

Well, if you’re developing ASP.NET, PHP, or Ruby on Rails web applications, you’re in luck. Just set a property, or change a config file, and you’re golden.

But what about J2EE? Well, there is no HttpOnly property supported in the Cookie interface. You can set your own cookies to be HttpOnly:

response.setHeader(“Set-Cookie”, “originalcookiename=originalvalue; HTTPOnly”);

But that doesn’t work for JSESSIOND, the J2EE session identifier, since it is handled by the container. So, you’re out of luck. Or are you?

After fiddling around with HacmeBooks, the Foundstone Free Tool for demonstrating common web application vulnerabilities in Java, I was able to get the HttpOnly property set on the JSESSIONID cookie.

Here’s the code below (from a ServletFilter):

// Check if this is where the JSESSIONID is being set (assuming that JSESSIONID is the only cookie used) if (response.containsHeader(“SET-COOKIE”)){    String sessionid = request.getSession().getId();    response.setHeader(“SET-COOKIE”, “JSESSIONID=” + sessionid + “; Path=/HacmeBooks; HttpOnly”);}// Continue down the Filter Chainchain.doFilter(request, response);

This code is far from ideal – it essentially replaces the JSESSIONID cookie set by the server, so any properties (path, expires, secure, etc.) that the server sets have to be specified in the code. It also won’t work if other cookies besides JSESSIONID are being used (you could fix this by looking at the request and making sure JSESSIONID isn’t already set).

However, until Java gets around to supporting HttpOnly cleanly, this is the best way I could figure to set this property on the JSESSIONID.

*BONUS*

I mentioned that there are some people who have taken HttpOnly to task for being an incomplete mitigation for XSS.

Jeremiah Grossman talks about using the HTTP TRACE verb to get access to HttpOnly cookies in the reflected request.

pdp suggests that HttpOnly is meaningless because most attackers don’t really care about session hijacking through XSS – there are more damaging attacks that can be leveraged through XSS.

RSnake points out that in FireFox XMLHttpRequest can be used to access the cookie and bypass HttpOnly. Additionally, some older, obscure browsers (IE5 on Mac, WebTV) choke and die on the header instead of safely ignoring it.

Amit Klein suggest several different methods, including some mentioned above, for bypassing the HttpOnly protection.

I think for all of its shortcomings, HttpOnly is still a good idea. The bugs will get worked out, and everyone will be a little safer.