Spring Security无效的remember-me令牌(系列/令牌)不匹配,暗示以前的cookie窃取攻击

mzmfm0qo  于 2023-02-11  发布在  Spring
关注(0)|答案(4)|浏览(250)

我有一个使用SpringSecurity3.1.2的GWT应用程序在tomcat 7中运行。我正在使用UsernamePasswordAuthenticationFilter和PersistentTokenBasedRememberMeServices来持久化数据库上的登录。此外,我也在使用Tomcat PersistentManager将会话保存在数据库中。现在我的问题是每次尝试登录时都会收到 * 无效的remember-me令牌(系列/令牌)不匹配CookieTheftException*(我在下面添加了堆栈)。我尝试从tomcat_sessions表中删除会话,如下所示
1.关机雄猫
1.从tomcat_sessions表中删除记录
1.启动Tomcat
1.尝试再次登录到我收到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)
k3bvogb1

k3bvogb11#

为了让我们达成共识,我将首先花一分钟来解释我是如何理解这种持久令牌机制的工作原理的。
从头开始(persistent_logins表中没有条目):

    • 登录成功时:**将使用一些随机散列为用户创建一个永久令牌。将为用户创建一个cookie,其中包含令牌详细信息。将为用户创建一个会话。

只要用户仍然具有活动会话,则在认证时将不调用记住我功能。

    • 用户会话过期后:**Remember me功能启动并使用cookie从数据库中获取持久令牌。如果持久令牌与cookie中的令牌匹配,则每个人都很高兴用户通过了身份验证,生成新的随机哈希,并使用它更新持久令牌,用户的cookie也会为后续请求更新。
    • 但是如果cookie中的令牌与持久化令牌不匹配,**那么你会得到一个CookieTheftException。令牌不匹配最常见的原因是2个或更多的请求被快速连续地触发,其中第一个请求将通过,为后面的请求生成新的哈希值,但第二个请求仍然有旧的令牌,从而导致异常。

为了在很大程度上避免CookieTheftException,请确保对Web应用内容(如图像、字体、脚本等)的请求不经过Springs身份验证过滤器。为此,只需在常规安全配置之上添加另一个<http>配置,并指定您不希望对资源请求进行任何安全保护(使用相关路径,而不是/resources/**):

<http pattern="/resources/**" security="none"/>
<http ... (normal config) ...

(For Java配置请参见此处:How do I define http "security = 'none' in JavaConfig?
如果你从数据库中删除了一个用户的令牌(并且他们的会话已经过期),那么这个用户将在下一次请求时被注销。所以你所说的自动重新创建持久令牌(在persistent_logins表中)是没有意义的,我非常怀疑这种情况。PersistentTokenRepositorycreateNewToken(PersistentRememberMeToken token)方法只在登录成功时被调用。
最后,如果您仍然会得到异常,则附加PersistentTokenBasedRememberMeServices的源代码并在processAutoLoginCookie方法中放置一个断点以查看哪个请求导致了CookieTheftException会有所帮助。
希望这能帮上忙。

k75qkfdt

k75qkfdt2#

我遇到了同样的错误,注意到它试图自动登录安全链被忽略的每个请求。

public void configure(WebSecurity web) throws Exception {
    web
        .debug(true)
        .ignoring()
        .antMatchers("/css/**", "/js/**", "/img/**");
}

在此之后,我注意到js文件和css文件跳过了安全链,我删除了这些Map,并记得我开始工作,因为它应该。

public void configure(WebSecurity web) throws Exception {
    web
        .debug(true)
        .ignoring()
        .antMatchers("/img/**");
}
8ljdwjyq

8ljdwjyq3#

我的配置中缺少的部分是RememberMeAuthenticationProvider。(http://docs.spring.io/spring-security/站点/docs/3.2.2.RELEASE/参考/htmlsingle/#记住我的实现)
请注意,RememberMeAuthenticationProvider的包已更改,与文档中的包不同。

    • 不要忘记为基于持久性令牌的RememberMeServices和RememberMeAuthenticationProvider定义相同的密钥**

这是我的配置:

<s:http auto-config="false"
            use-expressions="true"
            create-session="ifRequired">
        <s:remember-me services-ref="rememberMeServices"
                       authentication-success-handler-ref="rememberMeAuthenticationSuccessHandler"/>
...
</s:http>

 <bean id="rememberMeServices"
          class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
     <constructor-arg index="0" value="${remember.me.key}" />
...
</bean>

<bean id="rememberMeAuthenticationProvider" class=
        "org.springframework.security.authentication.RememberMeAuthenticationProvider">
        <property name="key" value="${remember.me.key}"/>
    </bean>

<s:authentication-manager alias="authenticationManager">
        <s:authentication-provider ref="rememberMeAuthenticationProvider" />
...
    </s:authentication-manager>

马库斯·库切的回答让我明白了一切。谢谢!

jgovgodb

jgovgodb4#

修正了令牌历史记录的问题-从这个评论中得到了这个想法

  1. Create table,能够在每个系列中存储多个令牌
  2. Create repository(作业质量)
    1.实现remember me service以检查多个令牌而不是最后一个令牌
    要模拟PersistentTokenBasedRememberMeServices的原始行为,可以将.limit(1)添加到CustomPersistentTokenRepository.findAllBySeries方法

相关问题