Spring Security无效的remember-me令牌(系列/令牌)不匹配.意味着以前的cookie盗窃攻击

Sam*_*ush 10 spring spring-security remember-me tomcat7

我有一个使用在tomcat 7中运行的Spring Security3.1.2的GWT应用程序.我使用UsernamePasswordAuthenticationFilter和PersistentTokenBasedRememberMeServices来持久登录数据库.此外,我正在使用tomcat PersistentManager来保存数据库中的会话.现在我的问题是,每次我尝试登录我得到无效记住我令牌(系列/令牌)不匹配CookieTheftException(我添加了下面的堆栈).我尝试从tomcat_sessions表中删除会话,如下所示

  1. 关闭tomcat
  2. 从tomcat_sessions表中删除记录
  3. 启动tomcat
  4. 尝试登录到我再次获得CookieTheftException的应用程序...

我还注意到,即使删除了tomcat_sessions表中的所有记录,并且当我重新启动tomcat时,tomcat_sessions也会被我之前删除的所有会话填满...

我还删除了Spring persistent_logins表中的所有记录并禁用了tomcat PersistentManager但仍然遇到了同样的问题......

任何想法可能是什么问题?谢谢

SEVERE: Servlet.service() for servlet [springMvcServlet] in context with path [/brate] threw exception
org.springframework.security.web.authentication.rememberme.CookieTheftException: Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
    at org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.processAutoLoginCookie(PersistentTokenBasedRememberMeServices.java:102)
    at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:115)
    at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:97)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.brate.admin.server.servlet.crawler.GoogleBotFilter.doFilter(GoogleBotFilter.java:202)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:695)
Run Code Online (Sandbox Code Playgroud)

Mar*_*zee 26

为了让我们在同一页面上,我将首先花一点时间来解释我如何理解这种持久性令牌机制的工作原理.

从头开始(表中没有条目persistent_logins):

登录成功时: 将使用一些随机哈希为用户创建持久性令牌.为用户创建一个cookie,其上包含令牌详细信息.为用户创建会话.

只要用户仍然有活动会话,那么在记住身份验证时就不会记住我的功能.

用户会话到期后: 记住我的功能启动并使用cookie从数据库中获取持久性令牌.如果持久化令牌与cookie中的令牌匹配,则每个人都很高兴,因为用户获得了身份验证,生成了新的随机哈希,并使用它更新了持久令牌,并且用户的cookie也会随后更新.

但是如果cookie中的令牌与持久令牌的令牌不匹配,那么您将获得CookieTheftException.令牌不匹配的最常见原因是快速连续发出了2个或更多请求,其中第一个请求将通过,为后续请求生成新哈希,但第二个请求仍将具有旧令牌它因此导致例外.

要在很大程度上避免CookieTheftException,请确保对您的webapp内容(如图像,字体,脚本等)的请求不会通过Springs身份验证筛选器.要做到这一点,只需<http>在正常安全配置之上添加另一个配置,并指定您不希望对资源请求有任何安全性(使用相关路径代替/resources/**):

<http pattern="/resources/**" security="none"/>
<http ... (normal config) ... 
Run Code Online (Sandbox Code Playgroud)

(对于Java Config,请参阅:如何在JavaConfig中定义http"security ='none'?)

如果从数据库中删除用户的令牌(并且其会话已过期),则用户将在下一个请求时注销.所以你所说的关于持久性令牌(在persistent_logins表格中)自动重新创建的内容几乎没有意义,我非常怀疑是这种情况.该PersistentTokenRepositorycreateNewToken(PersistentRememberMeToken token)方法只能得到的号召登录成功.

最后,如果您仍然获得异常,则有助于附加源的源PersistentTokenBasedRememberMeServices并在processAutoLoginCookie方法中放置断点以查看哪个请求导致CookieTheftException.

我希望这有帮助.

  • @Markus:我们也面临着类似的问题,正如您所建议的,即使我们确保了以下几点:“要在很大程度上避免CookieTheftException,请确保对您Web应用程序内容(例如图像,字体,脚本等)的请求不会发送通过Springs身份验证过滤器。” 我们仍然会遇到此问题,因为在我们的案例中,快速连续触发了2个/更多rest调用,并使用相同的cookie值。即使在第一个rest调用的响应标头中,也希望SET COOKIE更新RememberMe cookie值。但是在此之前会触发第二个呼叫。有什么建议么。-Hemant (2认同)