Monday, March 19, 2012

Rescue the Session Fixation Problem in Java with Apache Tomcat Valves


1. Introduction 

Session Fixation is a web application vulnerability found in many web-based applications which uses same session identifier (session ID) after login. This allows the attacker to exploit the vulnerability by setting another user's session ID. To avoid this, we must create a new session after successful authentication.

2. How to do it in JAVA ?  

Basically, after successful authentication, we have to invalidate the current session and create a new one.
Following is the code snippet to do the same.



     // request is of type HTTPServletRequest
     HttpSession session = request.getSession(); 
     session.invalidate();
     request.getSession(true);
       
 

getSession() method gives the current session object. To create a new session call the same method with 'true' parameter. Passing 'false' to the method is same as calling method with no parameters.

3. Problem with above approach :

Above logic will work only if the session is created over HTTP. But, it won't work if the session is created over HTTPS. To represent the HTTPS session there is a different class SSLSession. I tried various things and also searched on Google but I had no luck. Finally, I came to know about Tomcat Valves.

4. What is Tomcat Valve ?

Tomcat Valves are special filters which intercepts all request before they get processed. Some of you may be familiar with servlet filters used by web applications to do application-specific processing of the request. The key distinction between servlet filters and Tomcat Valves is that Valves are applied and controlled through the configuration of the application server. Depending on the container definition where the Valve element appears in the Tomcat configuration, the valve could be configured for all applications on the application server, a subset of applications, or even a single application. Apache Tomcat comes with a number of valves, including AccessLogValve, RemoteAddressFilter, SingleSignOnValve, and others.

You can also create your own valve by 2 ways :
a. Extending ValueBase class
b. Implementing Value interface.

If you are going with second way you have to implement some other unnecessary methods also. So, I would prefer the first one. In the first one you just need to override the invoke method.

5. Tomcat Valve Example to resolve the Session Fixation problem :

Here is the example of SessionFixationValve which I have used.





package org.tomcat.valves.sessionFixation;

import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.catalina.Session;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.authenticator.SavedRequest;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

public class sessionFixationValve extends ValveBase{
 
 private String authenticationUrl = "/j_acegi_security_check";
 
 public void setAuthenticationUrl(String authenticationUrl) {
  
  if(authenticationUrl.equals("")){
     throw new IllegalArgumentException("String is empty.");   
  }
  this.authenticationUrl = authenticationUrl;
 }

 @Override 
 public void invoke(Request req, Response response) throws IOException,
   ServletException {  
  // check for the login URI, only after a login
  // we want to renew the session  
  if (req.getRequestURI().contains(authenticationUrl)) {

     // save old session
    Session oldSession = req.getSessionInternal(true);
    SavedRequest saved = (SavedRequest) oldSession.
     getNote(Constants.FORM_REQUEST_NOTE);

    // invalidate old session
    req.getSession(true).invalidate();
    req.setRequestedSessionId(null);
    req.clearCookies();

    // create a new session and set it to the request
    Session newSession = req.getSessionInternal(true);
    req.setRequestedSessionId(newSession.getId());

    // copy data from the old session
    // to the new one
    if (saved != null) {
      newSession.setNote(Constants.FORM_REQUEST_NOTE, saved);
    }   
    
  } 
  // after processing the request forward it
  getNext().invoke(req, response);
 }

}



6. Installing the Valve :

To make the Valve work, use following steps :

1. Create a jar for above code and put it in the $TOMCAT_HOME/server/lib/.
2. Declare valve in the server.xml. Put it under the Host node.
3. Set the authenticationUrl value as per your web application.




<Host>
  <Valve className="org.tomcat.valves.sessionFixation.sessionFixationValve" authenticationUrl="/j_acegi_security_check"/>
</Host>



7. Reference:

This solution was devloped by Daniel Wasser and Thomas Schmidt.

Get the more information about Tomcat API's here.



2 comments:

  1. Very helpful article for me, got to know many things about Tomcat Valve. Thanks Akshay.

    ReplyDelete
  2. nice article aks... :)
    the second approach i.e.Tomcat Valve will only work if the web application is
    deployed on tomcat server and not with other server...

    ReplyDelete