views:

1001

answers:

2

I am using Spring Security's RememberMe Services to keep a user authenticated.

I would like to find a simple way to have the RememberMe cookie set as a session cookie rather than with a fixed expiration time. For my application, the cookie should persist until the user closes the browser.

Any suggestions on how to best implement this? Any concerns on this being a potential security problem?

The primary reason for doing so is that with a cookie-based token, any of the servers behind our load balancer can service a protected request without relying on the user's Authentication to be stored in an HttpSession. In fact, I have explicitly told Spring Security to never create sessions using the namespace. Further, we are using Amazon's Elastic Load Balancing, and so sticky sessions are not supported.

NB: Although I am aware that as of Apr. 08, Amazon now supports sticky sessions, I still do not want to use them for a handful of other reasons. Namely that the untimely demise of one server would still cause the loss of sessions for all users associated with it. http://aws.amazon.com/about-aws/whats-new/2010/04/08/support-for-session-stickiness-in-elastic-load-balancing/

A: 

To have session work properly with load balancing I would have your session data stored in a sql database.

The cookie should always be a random value that expire. There are cases where you can store state as a cookie value and it not be a secuirty hazard, such as the users preferred language, but this should be avoided as much as possible. Turning HttpOnlyCookies on, is a great idea.

Read A3: "Broken Authentication and Session Management" in the OWASP top 10 for 2010. One important point in this section is that https must be used for the entire session. If the session is lasting for a very long time, then this is even more important.

Also keep in mind that "Remember Me" creates a large window in which an attacker can "ride" on the session. This gives an attacker a very long time (Months?) in which he can deliver a CSRF attack. Even if you have CSRF protection an attacker can still ride on a session with XSS and XmlHttpRequest (HttpOnlyCookies will prevent a full hijack). "Remember Me" makes other threats like xss, csrf, sniffing more serious. As long as these vulnerabilities have been addressed, then you shouldn't have a problem with real world hackers.

The easiest (and secure) approach to implement a "remember me" feature would be to modify the session timeout to make it very large (a few months). If the "remember me" checkbox is unchecked then store a session variable with a new timeout (1 day from login). Keep in mind that even if the cookie is deleted by the browser when it is closed the session still is active on the server side. If the session id stolen, then it can still be used.

Rook
What about a custom RememberMe filter than creates a new token on each request. The new token can have a short lifespan, e.g. 20 minutes. If the user does nothing, the token expires. If the user makes another request in the 20 minute window, a new 20 minute window is created. If the user's session is stolen somehow, changing the user's password will still invalidate any valid tokens in the wild... thoughts?
Jarrod
I remember where I heard this idea before... it requires persistence of the token to a database, but not an HttpSession:http://jaspan.com/improved_persistent_login_cookie_best_practicePerhaps I'll look into subclassing the PersistentTokenBasedRememberMeService in Spring Security.
Jarrod
A: 

Spring Security 3 does not offer configuration of how the cookie is generated. You have to override the default behaviour:

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;

/** Cookie expires on session. */
 public class PersistentTokenBasedRememberMeServicesCustom extends
   PersistentTokenBasedRememberMeServices {

  /** only needed because super throws exception. */
  public PersistentTokenBasedRememberMeServicesCustom() throws Exception {
    super();
  }

  /** Copy of code of inherited class + setting cookieExpiration, */
  @Override
  protected void setCookie(String[] tokens, int maxAge,
      HttpServletRequest request, HttpServletResponse response) {
    String cookieValue = encodeCookie(tokens);
    Cookie cookie = new Cookie(getCookieName(), cookieValue);
    //cookie.setMaxAge(maxAge); 
    cookie.setPath("/");
    cookie.setSecure(false); // no getter available in super, so always false

    response.addCookie(cookie);
  }
}

Make sure, you use this customized PersistentTokenBasedRememberMeServices for you're rememberMeService by adding the class name to it's bean configuration:

<beans:bean id="rememberMeServices"
 class="my.custom.spring.PersistentTokenBasedRememberMeServicesCustom"/>
Kdeveloper