Spring Boot、Spring Security 和 Thymeleaf:将 CsrfFilter 应用到带有表单的网站

Posted

技术标签:

【中文标题】Spring Boot、Spring Security 和 Thymeleaf:将 CsrfFilter 应用到带有表单的网站【英文标题】:Spring Boot, Spring Security and Thymeleaf: Apply CsrfFilter to website with form 【发布时间】:2015-10-21 20:33:07 【问题描述】:

我正在使用带有 Thymeleaf 的 Spring Security,并希望在同时使用 CSRF 保护的不同站点上创建登录和注册表单。与以下 WebSecurity 配置一样,保护登录站点很容易

@Override
protected void configure(final HttpSecurity http) throws Exception 
    http
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .requestMatchers()
            .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated();

Spring 通常支持通过在 configure 方法中构建的 Security Filter Chain 添加 CSRF 保护。此过滤器链包含一个 CSRFFilter,用于添加/评估 CSRF 令牌。然后,此过滤器链将用于上述配置中定义的所有匹配项。获取应用于请求的过滤器的机制可以在方法中找到here

doFilterInternal(ServletRequest, ServletResponse, FilterChain)

问题是,如果我将“/register”站点添加到此配置中,用户首先会被重定向到“/login”站点。如果我不将其添加到上述配置中,则不会应用提到的 FilterChain(因此不会应用 CsrfFilter)。

所以我想要重用“/register”站点的过滤器链中的CsrfFilter,但我不知道该怎么做。

我更喜欢这种方法而不是其他想法,例如按照 here 或 here 的建议编写自定义 CSRF 过滤器。

【问题讨论】:

【参考方案1】:

从所有这些我了解到问题是您希望人们无需先登录即可访问/注册。这是一个简单的修复:

@Override
protected void configure(final HttpSecurity http) throws Exception 
    http
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .requestMatchers()
// add this line
.antMatchers("/register").permitAll().and

//
            .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated();

【讨论】:

嗨阿瑟尔!那不是问题。我的目标是在我的 /register 表单中启用 CSRF 保护。 Spring 支持通过在 configure 方法中构建的 Security Filter Chain 通常添加 CSRF 保护。此过滤器链包含一个 CSRFFilter,用于添加/评估 CSRF 令牌。如果我按照您建议的方式添加 /register 站点,过滤器链将忽略该站点,因此将不会使用 CSRF 保护。我在帖子中添加的链接建议了添加手动 CSRF 保护机制的方法,但我宁愿重用 Spring 现有的。 我一定是误会了。因此,您创建了一个自定义安全过滤器链而不是使用现有的安全过滤器链,从而导致问题?【参考方案2】:

原来 Spring Security Filter 链适用于提供给 requestMatchers().antMatchers() 的列表中提到的所有端点。

所以要对不是登录站点的站点使用 CSRF 保护,我只需将其添加到此列表中,然后允许对其进行所有访问,因此不会重定向到登录页面。我的最终配置如下所示

@Override
protected void configure(final HttpSecurity http) throws Exception 
    http.requestMatchers()
            // consider these patterns for this config and the Security Filter Chain
            .antMatchers("/login", "/register", "/oauth/authorize", "/oauth/confirm_access", "/oauth/token_key",
                    "/oauth/check_token", "/oauth/error")
            .and()
            // define authorization behaviour
            .authorizeRequests()
            // /register is allowed by anyone
            .antMatchers("/register").permitAll()
            // /oauth/authorize needs authentication; enables redirect to /login
            .antMatchers("/oauth/authorize").authenticated()
            // any other request in the patterns above are forbidden
            .anyRequest().denyAll()
            .and()
            .formLogin()
            // we have a custom login page at /login
            // that is permitted to everyone
            .loginPage("/login").permitAll();

【讨论】:

以上是关于Spring Boot、Spring Security 和 Thymeleaf:将 CsrfFilter 应用到带有表单的网站的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security常用过滤器介绍

Grails Spring Core 安全插件 - 无法解析类

Spring security @secure 不适用于角色层次结构

Spring Boot 学习例子

Spring Boot 2Spring Boot CLI

Spring Security OAuth - 访问此资源需要完全身份验证