2010-04-09 75 views
6

我使用Spring Security的RememberMe服务来保持用户身份验证。Spring安全记忆服务会话Cookie

我想找一个简单的方法将RememberMe cookie设置为会话cookie而不是固定的到期时间。对于我的应用程序,cookie应该保持到用户关闭浏览器。

关于如何最好地实现这一点的任何建议?对此有任何担忧是潜在的安全问题?

这样做的主要原因是,使用基于cookie的令牌时,负载均衡器后面的任何服务器都可以为受保护的请求提供服务,而不依赖于用户的身份验证以存储在HttpSession中。实际上,我明确地告诉Spring Security永远不要使用名称空间创建会话。此外,我们正在使用Amazon的Elastic Load Balancing,因此不支持粘性会话。

注意:尽管我知道,截至2008年4月,亚马逊现在支持粘性会话,但我仍然不希望将其用于少数其他原因。即一台服务器不合时宜的消亡仍然会导致与其相关的所有用户的会话丢失。 http://aws.amazon.com/about-aws/whats-new/2010/04/08/support-for-session-stickiness-in-elastic-load-balancing/

+0

为什么你不是简单地实现自己的RememberMe实现吗?这很容易。 – lexicore 2010-04-09 14:58:59

+0

重复? http://chackoverflow.com/questions/2594960/best-practice-to-implement-secure-remember-me – rook 2010-04-09 15:20:32

+0

@lexicore人员实施他们自己的会话可能会给您的网络应用带来真正的破坏。不要重新发明风团。阅读我的帖子上的“重复?”上面的问题。 – rook 2010-04-09 15:21:44

回答

3

要使会话正常工作与负载平衡我会让你的会话数据存储在sql数据库。

该Cookie应该始终是一个过期的随机值。在某些情况下,您可以将状态存储为Cookie值,并且不会造成安全隐患,例如用户首选的语言,但应尽可能避免这种情况。打开HttpOnlyCookies,是一个好主意。

阅读A3:2010年OWASP前10名中的“破坏的身份验证和会话管理”。本节中重要的一点是,必须将HTTPS用于整个会话。如果会议持续很长时间,那么这更重要。

另外请记住,“记住我”创建了一个大型窗口,攻击者可以在该窗口上“骑”会话。这给了攻击者很长的时间(几个月?),他可以提供CSRF攻击。即使你拥有CSRF保护,攻击者仍然可以使用XSS和XmlHttpRequest进行会话(HttpOnlyCookies将防止完全劫持)。 “记住我”让其他威胁如xss,csrf,嗅探更严重。只要这些漏洞得到解决,那么你就不应该对真实世界的黑客有问题。

实现“记住我”功能的最简单(也是安全的)方法是修改会话超时以使其非常大(几个月)。如果“记住我”复选框未被选中,则会使用新的超时(登录后1天)存储会话变量。请记住,即使cookie在浏览器关闭时被删除,该会话在服务器端仍然处于活动状态。如果会话ID被盗,那么它仍然可以使用。

+0

自定义的RememberMe过滤器与在每个请求上创建新令牌相比如何。新的令牌可以具有较短的使用期限,例如20分钟。如果用户什么都不做,令牌就会过期。如果用户在20分钟窗口中发出另一个请求,则会创建一个新的20分钟窗口。如果用户的会话以某种方式被盗,更改用户的密码仍然会使野外任何有效的令牌失效......思考? – 2010-04-14 13:15:46

+0

我记得我之前听说过这个想法......它需要持久化令牌到数据库,但不需要HttpSession: http://jaspan.com/improved_persistent_login_cookie_best_practice 也许我会研究在Spring中继承PersistentTokenBasedRememberMeService安全。 – 2010-04-14 14:07:52

5

Spring Security 3不提供如何生成cookie的配置。你必须覆盖默认行为:

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); 
    } 
} 

确保,对于您通过添加类名来它是rememberMeService您使用此定制对PersistentTokenBasedRememberMeServices的bean的配置:

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