当前位置: 首页 > 知识库问答 >
问题:

Spring CSRF覆盖安全XML配置中的“POST”注销行为

俞俊逸
2023-03-14

目前,我们的传统应用程序的Spring CSRF解决方案存在一个问题,因为CSRF实现改变了默认Spring security Spring security配置sis的行为,如下所示:

<http pattern="">
...
<logout
                logout-url="/logout"
                delete-cookies="..."
                success-handler-ref="logoutSuccessHandler"
                />
<csrf/>
</http>

org。springframework。安全配置。注释。网状物配置器。注销配置器注销配置器。根据Spring文档:

添加CSRF将更新LogoutFilter以仅使用HTTP POST。这将确保注销需要CSRF令牌,并且恶意用户无法强制注销您的用户。

进行此更改的代码如下:

 private RequestMatcher getLogoutRequestMatcher(H http) {
        if(logoutRequestMatcher != null) {
            return logoutRequestMatcher;
        }
        if(http.getConfigurer(CsrfConfigurer.class) != null) {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
        } else {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
        }
        return this.logoutRequestMatcher;
    }

一般来说,对于CSRF保护来说,这种行为是完全合理的。但对我来说,这个实现不灵活是非常奇怪的(为什么要硬编码真正的实现,而不是autowire依赖?)。

问题是,我们的应用程序是以这样的方式构建的:在常规Spring注销之前,它会在Spring控制器中执行额外的清理。它主要是以一种定制的方式实现的。所以,将注销链接更改为执行POST不是一个选项,因为主要是在自定义控制器上执行清理。

为了使用特定的方法,似乎只有一种可能的解决方案:

@RequestMapping(value = "/logout", method = RequestMethod.GET) //or it can be a post
    public String logout() {
// 1. Perform Clean up
// 2. Decide whether to logout or redirect to other page
// 3. Perform redirect based on decision
}

//如果决定注销,这将转到这个Controller方法:

  @RequestMapping(value = "csrflogout", method = RequestMethod.GET)
    public void csrfLogout(){
//1 Create manual post request
//2. Copy session information
//3. Perform Post to logout URL that is specified in security xml
     }

通常,从代码质量的角度来看,这种方法并不好。因此,有两个问题:

  1. 为什么在Spring中进行如此严格的实现,并且不提供任何可见的可能性来覆盖它(特别是我提供了如何创建它的代码示例)?
  2. 任何解决上述问题的好方法。

共有3个答案

鱼宜
2023-03-14

在Internet Explorer 11更新后,我看到了相同的错误。CsrfConfigurer。类不为null,注销时应为post。

if(http.getConfigurer(CsrfConfigurer.class) != null) {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
        } else {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
        }

我解决了我的问题通过绕过logoutFilter并插入新的过滤器到Spring安全

下面是一个例子。

    <beans:bean id="logoutAntPathRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
            <beans:constructor-arg value="/logout"/>
        </beans:bean>

        <beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">

        </beans:bean>


        <beans:bean id="cookieClearingLogoutHandler" class="org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler">
            <beans:constructor-arg value="JSESSIONID"/>
        </beans:bean>

        <beans:bean id="logoutFilter"
              class="org.springframework.security.web.authentication.logout.LogoutFilter">
            <beans:constructor-arg  name="logoutSuccessUrl" value="/login"/>
            <beans:constructor-arg  name="handlers">
                <beans:list>
                    <beans:ref bean="securityContextLogoutHandler" />
                    <beans:ref bean="cookieClearingLogoutHandler" />
                </beans:list>
            </beans:constructor-arg>
            <beans:property name="filterProcessesUrl" value="/logout"/>
            <beans:property name="logoutRequestMatcher" ref="logoutAntPathRequestMatcher"/>
        </beans:bean>


<http>
...
<sec:custom-filter ref="logoutFilter" after="LOGOUT_FILTER"/>
...
</http>
孟安民
2023-03-14

基本上,主要的复杂性在于在Spring Security XML上下文中覆盖logoutFilter,以使用org的默认实现。springframework。安全网状物util。matcher。AntPathRequestMatcher(用于“获取”而不是“发布”请求)。为了做到这一点,在安全xml上下文中添加了几个bean:

 <bean id="logoutAntPathRequestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
        <constructor-arg value="logout" />
    </bean>

以及注销过滤器本身:

<bean id="logoutFilter"
    class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <constructor-arg  name="logoutSuccessHandler" ref="logoutSuccessHandler"/>
    <constructor-arg  name="handlers">
        <list>
            <ref bean="securityContextLogoutHandler" />
            <ref bean="cookieClearingLogoutHandler" />
            <ref bean="csrfLogoutHandler" />
        </list>
    </constructor-arg>
    <property name="filterProcessesUrl" value="/logout"/>
    <property name="logoutRequestMatcher" ref="logoutAntPathRequestMatcher"/>
</bean>
柯国安
2023-03-14

您描述的行为是,如果您没有显式配置注销支持,但只启用它,那么如果您显式配置它,它将使用该配置。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}

参考指南中也记录了这一点。

然而,真正的解决方案是,你不应该使用控制器来实现额外的注销功能,而应该使用LogoutHandler。这将与Spring Security性很好地集成,您不需要重定向/转发到不同的URL。

 类似资料:
  • 因为我在我的项目中添加了一个外部jar文件,所以log4j配置是从log4j中获取的。外部jar文件中的xml。log4j。我的应用程序中的xml配置未得到应用。 有没有办法覆盖log4j。xml配置,使我的应用程序log4j。xml被选中了? EAR结构: \lib\externalJar\log4j。xml \appweb。war\WEB-INF\classes\log4j。xml 我可以在日

  • 问题内容: 我有一个结构如下的文件: 我想在命令行中覆盖。 对于其他值为简单类型(字符串,数字)的配置键,我可以使用进行覆盖,并且效果很好。 但是,我似乎找不到为 list 做到这一点的方法。在上面的示例中,我尝试将其设置为如下所示:,但是我得到了一个例外,即键值是字符串,而不是列表。 有没有一种方法可以通知类型安全配置库此值是一个列表? 问题答案: 为此,在1.0.1版中实现了另一种语法:

  • 4.2.4注销处理 logout元素通过导航到特定URL添加了对注销的支持。默认的注销URL是/logout,但是您可以使用logout-url属性将其设置为其他内容。有关其他可用属性的更多信息可以在命名空间附录中找到。 但是,在遵循文档中的安全设置后,URL/logout不会显示注销页面。相反,它显示 Spring Framework 4.1.6 Spring Security 4.0.0 we

  • 然后我们有这样的服务: 我的第一个bean是由@repository注释创建的,另一个bean是在Spring配置类中声明的: 如果我运行我的应用程序,SomeServiceImpl中的属性someDaoAnotherDataSource没有在配置类中声明我的bean,而是用注释存储库声明了bean。

  • If set to true, variables read in from config files will overwrite each other. Otherwise, the variables will be pushed onto an array. This is helpful if you want to store arrays of data in config file

  • 下面是我的pom.xml 这是我的主课 SecurityConfig.Class