Spring Security CSRF筛选器与登录页面上的会话管理冲突

Spring Security CSRF筛选器与登录页面上的会话管理冲突,spring,spring-security,csrf,Spring,Spring Security,Csrf,我正在修改一个项目以使用SpringSecurityCSRF保护,我得到了一个有趣的行为。在我的登录页面上,如果我刷新页面一次、三次、五次,等等。然后,当我放入适当的凭据时,它会因为CSRF失败而将我踢出,但如果我立即登录或在两次、四次、六次等刷新后登录,我就可以正常登录 我已经在为什么会发生这种情况方面取得了进展,但我不知道如何解决这个问题。似乎只有在每次other请求时才会生成一个新的CSRF令牌,即使每次请求结束时我都会生成一个新会话。深入研究Spring逻辑发现,以下事件序列最有可能发生

我正在修改一个项目以使用SpringSecurityCSRF保护,我得到了一个有趣的行为。在我的登录页面上,如果我刷新页面一次、三次、五次,等等。然后,当我放入适当的凭据时,它会因为CSRF失败而将我踢出,但如果我立即登录或在两次、四次、六次等刷新后登录,我就可以正常登录

我已经在为什么会发生这种情况方面取得了进展,但我不知道如何解决这个问题。似乎只有在每次other请求时才会生成一个新的CSRF令牌,即使每次请求结束时我都会生成一个新会话。深入研究Spring逻辑发现,以下事件序列最有可能发生:

  • 第一个请求我点击页面。CSRF筛选器创建一个排序为saveOnAccessSrftoken的令牌(T1),并将其添加为请求属性
  • 将创建一个新会话(S1)
  • JSP呈现,导致调用请求中的令牌(T1),而
    saveOnAccessSrftoken
    将令牌保存到会话(S1)
  • 我又翻了一遍。CSRF筛选器仍然可以看到旧会话(S1),因此从会话中获取
    DefaultCsrfToken
    ,并将其(旧令牌-T1)添加到请求中,而不是创建新的会话
  • 将创建一个新会话(S2)
  • JSP呈现,导致调用请求中的令牌(T1),但由于它是
    DefaultCsrfToken
    ,因此不会向会话(S2)添加任何内容
  • 我又翻了一遍。CSRF筛选器仍然可以看到旧会话(S2),但由于没有向该会话添加任何内容,因此它会创建一个排序为saveOnAccessScrftoken的新令牌(T2),并将其作为请求属性添加
  • 将创建一个新会话(S3)
  • JSP呈现,导致调用请求中的令牌(T2),而
    saveOnAccessSrftoken
    将令牌保存到会话(S3)
  • 我又翻了一遍。我相信你现在已经明白这是怎么重复的了
  • 我认为解决方案是在创建会话时进行更改,但我不知道如何进行更改。想法

    使用Spring 4.2.2和Spring Security 4.0.3

    以下是安全XML:

    <?xml version="1.0" encoding="UTF-8"?> 
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
    
    <http pattern="/resources/**" security="none" />        
    <http pattern="/WEB-INF/**" security="none" />
    <http pattern="/error/**" security="none" />
    <!-- Other unrelated URLs -->
    
    <!-- Configure Spring URL based Web Security  -->
    <http>
        <intercept-url pattern="/login**" access="permitAll"/>
        <!-- Other unrelated URLs -->
    
        <intercept-url pattern="/**" access="isFullyAuthenticated()"/> 
    
        <form-login login-page="/login" 
                    authentication-failure-url="/loginFailure?$general{login.fail.urlPostFix}" 
                    default-target-url="/afterSuccessfulLogin"
                    login-processing-url="/j_spring_security_check" /> 
    
        <logout delete-cookies="JSESSIONID"
                invalidate-session="false" 
                logout-success-url="/login" 
                logout-url="/logout" /> 
    
        <session-management invalid-session-url="/login?invalidSession=true" />
        <access-denied-handler error-page="/denied" />
        <headers disabled="true" />
    </http> 
    
    <authentication-manager> 
        <authentication-provider user-service-ref="adminSecurityService"> 
            <password-encoder ref="passwordEncoder"/>
        </authentication-provider> 
    </authentication-manager>
    
    <!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
    <beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder" />
    
    
    

    为什么还要创建一个新会话,您有自定义的登录表单还是使用默认的Spring安全表单?您使用的确切版本是什么?4.0.x(在本例中x是什么)。您还可以添加您的spring安全配置(或者您目前拥有的配置)。新会话创建在应用服务器上,我有一个自定义的登录表单。我在上面添加了其他信息。我知道会话是在哪里创建的,但为什么?已经有一个会话,应该呈现cookie,或者问题是,如果有会话,为什么它无效?假设您使用的是JSP,您可以将
    添加到页面中,这样只有Spring Security创建会话,而不是JSP。创建会话是因为它是一个登录页面。人们通常不希望在登录页面上保留会话,因为这样一来,旧登录的参数就有流失到新登录的风险。添加session=false不仅没有修复它,而且还以新的令人兴奋的方式破坏了登录(这在这里似乎不相关)。您能够修复您的问题吗?你是怎么做到的?为什么还要创建一个新的会话,你有一个自定义的登录表单,还是使用默认的Spring安全表单?您使用的确切版本是什么?4.0.x(在本例中x是什么)。您还可以添加您的spring安全配置(或者您目前拥有的配置)。新会话创建在应用服务器上,我有一个自定义的登录表单。我在上面添加了其他信息。我知道会话是在哪里创建的,但为什么?已经有一个会话,应该呈现cookie,或者问题是,如果有会话,为什么它无效?假设您使用的是JSP,您可以将
    添加到页面中,这样只有Spring Security创建会话,而不是JSP。创建会话是因为它是一个登录页面。人们通常不希望在登录页面上保留会话,因为这样一来,旧登录的参数就有流失到新登录的风险。添加session=false不仅没有修复它,而且还以新的令人兴奋的方式破坏了登录(这在这里似乎不相关)。您能够修复您的问题吗?你是怎么做到的?