Markus is a Developer Advocate at Red Hat and focuses on JBoss Middleware. He is working with Java EE servers from different vendors since more than 14 years and talks about his favorite topics around Java EE on conferences all over the world. He has been a principle consultant and worked with different customers on all kinds of Java EE related applications and solutions. Beside that he has always been a prolific blogger, writer and tech editor for different Java EE related books. He is the Java Community leader of the German DOAG e.V. and it's representative on the iJUG e.V. As a Java Champion and former ACE Director he is well known in the community. Markus is a DZone MVB and is not an employee of DZone and has posted 189 posts at DZone. You can read more from them at their website. View Full User Profile

Binding SSL-Sessions to HttpSessions in GlassFish

  • submit to reddit

You might have noticed, that I am working my way through the security principles regarding secure web applications at the moment. The main idea about this is to enable GlassFish to deliver high secure applications. One of the things making my brain hurt a bit is the Session Hijacking attack. It consists of the exploitation of the http session control mechanism, which is normally managed for a session token.

In our case the JSESSIONID. The Session Hijacking attack compromises the session token by stealing or predicting a valid session token to gain unauthorized access to the applications running on you GlassFish.
There are different type of possible attacks. See the OWASP page about that for details. If you are going to address this topic you have different options from an implementation perspective. This is what I am going to describe in this blog post.

SSL is your friend
The basic requirement for session hijack prevention is to use https for your applications. This primary assures, that it's not easy to a) sniff the session out of the http stream and prevents simple man-in-the-middle attacks. Running in very high secure environments requires installing ssl certificates to your GlassFish and running all http-listeners in secure mode.

Where to put and how to configure the JSESSIONID?
Before you start with further reading, you should be aware that the whole topic is about the Servlet spec and about containers. The spec itself requires the session tracking cookie to be most convenient for any user and defines many ways of storing and transmitting it. This is a behavior that is undesired in high secure environments. So the first thing is to restrict the session tracking cookie to the minimum needed.

Specifies General Session Timeout in Minutes
Specifies whether any session tracking cookies created
by this web application will be marked as HttpOnly
Specifies whether any session tracking cookies created
by this web application will be marked as secure
Specifies whether JSESSIONID is added to the URL

What is also true is, that the spec would allow for "secure" HttpSession identifiers. In 7.1.2 it states, that
Secure Sockets Layer, the encryption technology used in the HTTPS protocol, has a
built-in mechanism allowing multiple requests from a client to be unambiguously
identified as being part of a session. A servlet container can easily use this data to
define a session.

Do my knowledge GlassFish does not implement this features up to now. So you have to work around this. Let's go:

HttpSession ID and SSL Session ID
Even if you are running SSL with the strongest certificates available, don't use URL-Rewriting and have httpOnly and secure enabled, nobody prevents you from man-in-the-browser attacks or client-side attacks. So, there are still some possibilities to gather the Session ID and use it from a different computer. If you are willing to implement some protection here, you are in need of some additional logic in your application which binds the SSL ID to your HttpSession ID.

The most obvious thing is to simply make both of them equal. The basic idea here is to take the SSL Session ID from the request and implement your own SessionIdValve which instantiates a HttpSession with that ID. Jan Luehe has a basic example how to achieve this with a GlassFish v2 on his blog. The only thing to do is to not take the client IP but the coyoReq.getAttribute("javax.servlet.request.ssl_session") and put it as HttpSession back to the request (see this forum discussion for more details). To be honest, I was not able to get this working with GlassFish 3 (see here). Don't worry: I don't like this solution anyway because it's simply not portable enough. You tie your logic very closely to the container you run in and so, you should avoid this approach in general.

Session Attributes
What I like a bit more is to use something like a HijackingPreventionFilter. This could be a simple @WebFilter that is mapped to any resource that should be protected

@WebFilter(dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD,
DispatcherType.INCLUDE, DispatcherType.ERROR}, urlPatterns = {"/*"})

On the first request it checks for an existing session and either does

chain.doFilter(request, response);

or checks some session attributes against the information in the actual request. The only prerequisite here is, that you have something in place to add the initial information to your newly created session. There are some places you could come up with. The best would probably be your login. Due to security reasons you should always _renew_ the HttpSession after a successful login. Afterwards you could assume that the request is from the client authenticating against your system. Just get the SSL Session ID and set it as HttpSession attribute there

String cidSize = (String)request.getAttribute("javax.servlet.request.key_size");
String cid = (String)request.getAttribute("javax.servlet.request.ssl_session");
session.setAttribute("CLIENT_SSL_ID", cid);

You noticed the cidSize attribute? The javax.servlet.request.ssl_session is not an official servlet supported attribute. Grizzly set's it, when the webcontainer asks to set ALL ssl attributes. So when you just ask for "javax.servlet.request.ssl_session", the webcontainer doesn't recognize it as known SSL attribute and nothing happens (Null), but when you first ask for the key size, it's getting recognized by the webcontainer and it asks Grizzly to set all known SSL attributes including the ssl_session.
Another good place could be an HttpSession listener. The big problem here still is, that you are programming against container features which prevent your application from being portable.

Custom HTTP Header variables
What really resolves the mess is, if you have any networking device or proxy in front of your GlassFish that simply puts the ssl-session-id as a custom header variable to your request. In this case you don't even have to care for it yourself, you simply change the code in your webfilter to check for your request headers.

String cidSize = httpRequest.getHeader("HEADER_CLIENT_SSL_ID");

The only drawback here is, that you basically lose the chance to locally run it without the proxy. So you need to put a startup class in place which adds your filter to the configuration if you are in production mode.

Conclusion: Security is painful
The higher your security requirements are, the more painful your development gets. That's the basic message. You don't have a single switch to turn on to secure your application but you have a lot of screws to tighten to get everything right. This post only shows a little bit from the complete story. What I would like to see is that the Servlet EG is taking some action defining more basic security into the spec.
What's also true is, that nobody should runs a high secure GlassFish without any kind of Enterprise Access Management (EAM) solution in place. Those typically address the described issues with their own plugins and tokens. Anyway, there are still some smaller installations out there suffering from the very little capabilities of todays Java EE servers.
Comments and suggestions? I would love to read them!



Published at DZone with permission of Markus Eisele, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)


Wujek Srujek replied on Tue, 2011/06/07 - 1:39am

About the 'javax.servlet.request.ssl_session' not being standard / always set, check out the specs: 3.8 SSL Attributes If a request has been transmitted over a secure protocol, such as HTTPS, this information must be exposed via the isSecure method of the ServletRequest interface. The Web container must expose the following attributes to the servlet programmer:
TABLE 3-3 Protocol Attributes
Attribute                      |     Attribute Name                                      |    Java Type
cipher suite                  |     javax.servlet.request.cipher_suite           |    String
bit size of the algorithm|     javax.servlet.request.key_size                 |    Integer
SSL session id              |     javax.servlet.request.ssl_session_id|    String
If there is an SSL certificate associated with the request, it must be exposed (...)
So, seems you are using some GF specific attribute name, whereas there is another, standard option. Or is it what you wanted to say, and GF doesn't play along?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.