When it comes to session management, developers most likely think firstly of cookies and secondly of the servlet container which normaly takes care of this.
The problem with the former is that cookies are actually just one of two common J2EE session tracking mechanisms. According to the Servlet 2.4 specification, “when a client will not accept a cookie, URL rewriting may be used by the server as the basis for session tracking“. J2EE servers like Tomcat, WebLogic and most others follow this rule by default.
The problem with the later is that most J2EE servers do in fact a good job when providing session management functionality to their hosted applications from performance and reliability point of view. Security, however, is not one of these. In fact, security aspects of the session management are not even mentioned in the servlet spec at all, which makes it to a proprietary issue of the application server and to the web application, respectively. Each session tracking mechanism has its own group of weaknesses. All of them have to be considered, when both mechanisms are supported.
But what are this session related threats. Well first of all, the randomness of the id is not one of them. From what we now, the sessionid algorithms are pretty good implemented by all J2EE , guaranteeing a cryptographic random value, which will not be guessable by an attacker, especially not over the Internet.
The risks are different are specific to the tracking mechanism itself. Let’s start with cookies.
COOKIES
As I mentioned above, cookies are the default tracking mechanism according to the spec. A cookie will be set by the server in a HTTP response header like
Set-Cookie: JSESSIONID=123; Path=/MyApp; secure
and automatically inserted into the HTTP header of all requests (JSPs, images, html, you name it) as long as the restrictions from the Set-Cookie statement do apply.
These restrictions are:
- validity (default: end of browser session)
- scope (default: the whole host)
- protocol (default http and https)
The server does not now why it received a particular cookie from the client, tough, because the applied restrictions are not part of the corresponding cookie statement of the HTTP request. All what the server gets from the client is a name and a value of this cookie:
Cookie: JSESSIONID=123
This does, however, only apply to cookies according to RFC2109 (also known as V0 cookies), which the standard today, though. Cookies according to RFC2965, also known as V1 cookies, corrected this issue and will hopefully be the standart one day.
Why is this behaviour now so important? The problem of the way of how (v0) cookies are implemented is that this is an tracking mechanism which is controlled by the browser. When a browser requests a URL it has a valid cookie in his (cookie) jar for, it automatically attach this cookie to the request without the user’s knowledge. This is not only a potential privacy risk for the user; it is also a security risk for the web application.
By default, a cookie will be send to all applications on the same host. If there is one single insecure application with an XSS vulnerability, an attacker can disclose the session id and compromise all applications on the same host through it.
The other major risk of session tracking by cookies is Cross-site request forgery (CSRF), where an attacker silently executes an action on the behalf of an authenticated user by just sending a crafted URL to him. When the user clicks on this link and his browser will automatically sends the cookie with the request and the application will execute it, because it simply has no chance to figure wheter this request was deliberately send by the user or not.
URL Rewriting
URL rewriting is the technique of transporting the Session ID within a Unified Ressource Locater better known as URL. Clients without cookie functionality such as many mobile devices still depend on URL rewriting. In older J2EE servers, such as WebLogic 6 and earlier, this was once done within a query parameter. As of Servlet 2.3 specification
http://[host]/edit.jsp;jsessionid=123?param=1
The sessionid is placed here by the application. Within a servlet this is done with encodeURL() and encodeRedirectURL(), respectively.
But how can an application unintentionally support URL rewriting, when it does not consider it in any way. Well, this is quit easy. Most taglibs like the JSTL or Struts automatically support URL rewriting. Unlike to an HTTP header which transports cookies, a session IDs in a URL can be disclosed on many ways, for example:
- log files
- the browser history
- by copy-and-pasting it into an e-mail or posting
- the HTTP Referrer
If the session id is not renewed after the login, URL rewriting can also be used for another attack: Session Fixation. Here, an attacker goes to the site and grabs a URL, such as
The good thing of URL rewriting, however, is that session tracking is now controled by the server and application, respectively.
Which to Choose
Generally, it’s not a bad idea to only support one tracking mechanism, so you just have to deal with the threats of one of them. But which is the best to chose? Unfortunately, there is no absolute answer to this question. One group of experts say URL rewriting is better the other say cookies are. In fact, it really depends on how you rate the specific threats I talked about before.
Disabling cookies can easily be done with a WebLogic, WebSphere as well as a Tomcat server. In the case of Tomcat, for instance, you just have to add "cookies=no" to the application’s context declaration at server.xml.
Forcing cookies gets a lot trickier. At least when you use a Tomcat server, because there is no simpar option like "urlrewriting=no". And even if you use a WebSphere or WebLogic server which allows you to disable URL rewriting, you might want to react on a browser having with cookies disabled, which an appropriate error page.
This can be implemented with and simple sevlet filter like this:
public class CookieEnforcer implements Filter {
private String errorPage;
public void init(FilterConfig FilterConfig)
throws ServletException
{
if (FilterConfig != null) {
errorPage = FilterConfig.getInitParameter("error_page");
}
}
public void doFilter(ServletRequest req,
ServletResponse rsp,
FilterChain chain)
throws ServletException, IOException
{
HttpServletRequest httpReq = (HttpServletRequest) req;
HttpSession session = httpReq .getSession(false);
if ( (session != null) &&
(httpRequest.isRequestedSessionIdFromURL() ))
{
request.getRequestDispatcher(errorPage).forward(req,rsp);
}
else {
chain.doFilter(req,rsp);
}
}
public void destroy() {}
}
The corresponding declaration in the web.xml file has to look like this:
<filter>
<filter-name>CookieEnforcer</filter-name>
<filter-class>examples.CookieEnforcer </filter-class>
<init-param>
<param-name>error_page</param-name>
<param-value>error.jsp</param-value>
</init-param>
</filter>
The Silver Bullet
The silver bullet here is to establish a two factor session management which combines a factor from the URL with one of the header in some way. This can be most easily be done by utilizing cookies together with a page or session specific token in the URL.
In one of my next postings, I will describe more detailed on how to practically implement this approach under J2EE, for example with HDIV.