…or: HowTo prevent a session fixation attack. Most Security Papers (eg. the Security White Paper of the BSI ) suggest to renew the given Session id after a successful login. To archive this goal, you need to create a Valve which manipulates the session. According to the BSI paper there a four steps to renew the session id:
- store the old session
- invalidate the old session
- generate a new session
- copy the data of the old session into the new session
A valve is a special filter that operate outside of a web application. It intercepts all requests before they are subsequently processed. You can find out more about valves at the Tomcat documentation.
And here is the code for the valve:
public class RenewSessionValve implements Valve{
public void invoke(Request request, Response response)
throws IOException, ServletException {
// check for the login URI, only after a login
// we want to renew the session
if (req.getRequestURI().
contains("/portal/j_security_check")) {
// step 1: save old session
Session oldSession = req.getSessionInternal(true);
SavedRequest saved = (SavedRequest) oldSession.
getNote(Constants.FORM_REQUEST_NOTE);
// step 2: invalidate old session
req.getSession(true).invalidate();
req.setRequestedSessionId(null);
req.clearCookies();
// step 3: create a new session and set it to the request
Session newSession = req.getSessionInternal(true);
req.setRequestedSessionId(newSession.getId());
// step 4: copy data pointer from the old session
// to the new one
if (saved != null) {
newSession.setNote(Constants.FORM_REQUEST_NOTE, saved);
}
}
}
}
To make the Valve work, you need to declare it in the server.xml.
The reason why the session id is not renewed if you call request.getSessionInternal(true)
is because of the way how the catalina request class creates a new session.
If the old session id was stored in a cookie it creates a new session
using the old session id:
if (connector.getEmptySessionPath() && isRequestedSessionIdFromCookie()) {
session = manager.createSession(getRequestedSessionId());
}
The only way to prevent this is to call
request.RequestedSessionId(null) befor calling req.getSessionInternal(true)
This causes a manager.createSession(null) call in the request.doGetSession(), which generates a new session ID.
The JBoss Web 2.1.3 (which is a pimped Tomcat 6.0) has fixed this problem.
I would like to thank Thomas Schmidt who
developed this solution with me.