0

0

Spring Security 6下MockMvc CSRF测试的挑战与解决方案

碧海醫心

碧海醫心

发布时间:2025-11-24 22:05:28

|

262人浏览过

|

来源于php中文网

原创

spring security 6下mockmvc csrf测试的挑战与解决方案

本文探讨了在Spring Boot 3和Spring Security 6环境中,采用`XorCsrfTokenRequestAttributeHandler`进行CSRF防护时,`MockMvc`单元测试中`with(csrf())`失效的问题。文章详细介绍了该配置如何解决`WebClient`的端到端测试,同时提供了一种手动获取并注入CSRF令牌的`MockMvc`测试方案,以确保API接口在启用CSRF保护时的正确性验证。

Spring Security 6中CSRF防护机制的演进与挑战

跨站请求伪造(CSRF)是一种常见的网络攻击,Spring Security提供了强大的机制来防范此类攻击。随着Spring Boot 3和Spring Security 6的发布,CSRF处理机制也进行了一些优化和调整。为了增强安全性并更好地支持现代前端框架,Spring Security推荐使用CookieCsrfTokenRepository.withHttpOnlyFalse()配合XorCsrfTokenRequestAttributeHandler来管理CSRF令牌。

以下是典型的Spring Security 6 CSRF配置示例:

// Enable CSRF security
http.csrf { csrfConfigurer ->
    // see https://docs.spring.io/spring-security/reference/5.8/migration/servlet/exploits.html#_i_am_using_angularjs_or_another_javascript_framework
    val tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()
    val delegate = XorCsrfTokenRequestAttributeHandler()
    // set the name of the attribute the CsrfToken will be populated on
    delegate.setCsrfRequestAttributeName("_csrf")
    // Use only the handle() method of XorCsrfTokenRequestAttributeHandler and the
    // default implementation of resolveCsrfTokenValue() from CsrfTokenRequestHandler
    val requestHandler = CsrfTokenRequestHandler(delegate::handle)

    csrfConfigurer.csrfTokenRepository(tokenRepository)
    csrfConfigurer.csrfTokenRequestHandler(requestHandler)
}

这种配置方式在处理真实世界的HTTP请求时表现良好,特别是在端到端测试中,能够有效防范CSRF攻击。

端到端测试(WebClient)中的CSRF处理

在使用WebClient进行端到端测试时,客户端通常需要从服务器响应中获取CSRF令牌,并在后续的修改类请求(如POST、PUT、DELETE)中将其作为请求头或请求参数发送回去。上述CSRF配置与WebClient的FilterFunction结合,能够很好地实现这一流程。当遇到4xx客户端错误时,FilterFunction会检查响应中是否存在XSRF-TOKEN cookie,如果存在,则将其提取并添加到重试请求的X-XSRF-TOKEN头部和XSRF-TOKEN cookie中。

以下是WebClient中处理CSRF令牌的FilterFunction示例:

override fun filter(request: ClientRequest, next: ExchangeFunction): Mono =
    next.exchange(request)
        .flatMap { response: ClientResponse ->
            if (response.statusCode().is4xxClientError) {
                val csrfCookie = response.cookies().getFirst("XSRF-TOKEN")
                if (csrfCookie != null) {
                    val retryRequest: ClientRequest = ClientRequest.from(request)
                        .headers { httpHeaders -> httpHeaders.set("X-XSRF-TOKEN", csrfCookie.value) }
                        .cookies { cookies -> cookies.add("XSRF-TOKEN", csrfCookie.value) }
                        .build()
                    return@flatMap next.exchange(retryRequest)
                }
            }
            Mono.just(response)
        }

此过滤器确保了WebClient在与启用了CSRF保护的后端服务交互时,能够自动处理令牌的传递,从而使端到端测试能够顺利通过。

单元测试(MockMvc)中的CSRF困境

然而,上述有效的CSRF配置却在MockMvc的单元测试中引发了问题。MockMvc提供了一个便捷的with(csrf())方法,用于在测试请求中模拟CSRF令牌的注入。但在Spring Security 6中,当使用XorCsrfTokenRequestAttributeHandler时,SecurityMockMvcRequestPostProcessors.csrf()(即with(csrf()))不再能够正确生成或匹配所需的CSRF令牌。这导致原本能够通过的MockMvc测试开始失败,并报告CSRF令牌不匹配的错误。

以下是典型的失败MockMvc测试示例:

达芬奇
达芬奇

达芬奇——你的AI创作大师

下载
@Test
fun `create tender with copyFrom null should succeed and return 201 and the uuid`() {
    mockMvc
        .perform(
            post("/api/my/endpoint")
                .param("title", "Angebot 1")
                .param("copyFrom", null)
                .with(user(tendererTestUsers[0]))
                .with(csrf()) // 此处调用with(csrf())会导致测试失败
        )
        .andExpectAll(
            status().isCreated,
            content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON),
            jsonPath("$", `is`(notNullValue()))
        )
}

调试显示,with(csrf())生成的CSRF令牌与服务器期望的令牌不匹配,这是由于SecurityMockMvcRequestPostProcessors.csrf当前尚未支持XorCsrfTokenRequestAttributeHandler的内部机制。

MockMvc CSRF测试的解决方案

鉴于with(csrf())的局限性,目前的解决方案是在MockMvc测试中手动模拟CSRF令牌的获取和提交过程。这要求测试代码模拟浏览器或WebClient的行为,首先获取CSRF令牌,然后在需要CSRF保护的请求中手动添加。

步骤一:获取CSRF Token

首先,向Spring Security默认或自定义的CSRF端点(通常是/csrf)发送一个GET请求。这个请求会触发Spring Security生成一个新的CSRF令牌,并将其设置到响应的cookie中。

import org.springframework.mock.web.MockCookie;
import org.springframework.test.web.servlet.MvcResult;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

// ...
MvcResult mvcResult = this.mockMvc.perform(get("/csrf"))
                                   .andExpect(status().isOk()) // 确保请求成功
                                   .andReturn();
MockCookie csrfCookie = (MockCookie) mvcResult.getResponse().getCookie("XSRF-TOKEN");
// 检查cookie是否成功获取
if (csrfCookie == null) {
    throw new IllegalStateException("CSRF token cookie not found in /csrf response.");
}
String csrfTokenValue = csrfCookie.getValue();

步骤二:在请求中附加CSRF Token

获取到CSRF令牌的值和cookie后,在后续需要CSRF保护的POST、PUT或DELETE请求中,手动将令牌作为X-XSRF-TOKEN头部和XSRF-TOKEN cookie添加到请求中。

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

// ... 假设csrfCookie和csrfTokenValue已从步骤一获取
this.mockMvc.perform(post("/api/my/endpoint")
        .header("X-XSRF-TOKEN", csrfTokenValue) // 将令牌值添加到X-XSRF-TOKEN头部
        .cookie(csrfCookie) // 将整个CSRF cookie添加到请求中
        .param("title", "Angebot 1")
        .param("copyFrom", (String) null) // 注意:对于null参数,需要显式转换为String
        .with(user(tendererTestUsers[0])) // 其他认证信息
    )
    .andExpect(status().isCreated()); // 验证请求成功

通过这种手动方式,MockMvc测试能够正确地模拟带有CSRF令牌的请求,从而验证API接口在启用CSRF保护时的行为。

注意事项与总结

  • 临时解决方案: 这种手动处理CSRF令牌的方式是目前SecurityMockMvcRequestPostProcessors.csrf不支持XorCsrfTokenRequestAttributeHandler的临时解决方案。Spring Security社区已意识到此问题,并在GitHub上存在相关讨论(例如:spring-projects/spring-security#12826spring-projects/spring-security#12774)。未来版本可能会提供更优雅的内置支持。
  • 测试覆盖: 确保你的测试覆盖了CSRF令牌缺失、无效或过期等场景,以验证应用的健壮性。
  • 配置一致性: 无论是在生产环境、端到端测试还是单元测试中,保持CSRF配置的一致性至关重要。

总之,虽然Spring Security 6在CSRF防护方面带来了新的挑战,但通过理解其工作原理并采用适当的测试策略,我们仍然能够有效地进行单元测试和端到端测试,确保应用的安全性。在等待MockMvc对新CSRF处理器提供原生支持的同时,手动管理CSRF令牌是当前确保测试覆盖率的有效途径。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

102

2025.08.06

spring boot框架优点
spring boot框架优点

spring boot框架的优点有简化配置、快速开发、内嵌服务器、微服务支持、自动化测试和生态系统支持。本专题为大家提供spring boot相关的文章、下载、课程内容,供大家免费下载体验。

135

2023.09.05

spring框架有哪些
spring框架有哪些

spring框架有Spring Core、Spring MVC、Spring Data、Spring Security、Spring AOP和Spring Boot。详细介绍:1、Spring Core,通过将对象的创建和依赖关系的管理交给容器来实现,从而降低了组件之间的耦合度;2、Spring MVC,提供基于模型-视图-控制器的架构,用于开发灵活和可扩展的Web应用程序等。

389

2023.10.12

Java Spring Boot开发
Java Spring Boot开发

本专题围绕 Java 主流开发框架 Spring Boot 展开,系统讲解依赖注入、配置管理、数据访问、RESTful API、微服务架构与安全认证等核心知识,并通过电商平台、博客系统与企业管理系统等项目实战,帮助学员掌握使用 Spring Boot 快速开发高效、稳定的企业级应用。

68

2025.08.19

Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性
Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性

Spring Boot 是一个基于 Spring 框架的 Java 开发框架,它通过 约定优于配置的原则,大幅简化了 Spring 应用的初始搭建、配置和开发过程,让开发者可以快速构建独立的、生产级别的 Spring 应用,无需繁琐的样板配置,通常集成嵌入式服务器(如 Tomcat),提供“开箱即用”的体验,是构建微服务和 Web 应用的流行工具。

31

2025.12.22

Java Spring Boot 微服务实战
Java Spring Boot 微服务实战

本专题深入讲解 Java Spring Boot 在微服务架构中的应用,内容涵盖服务注册与发现、REST API开发、配置中心、负载均衡、熔断与限流、日志与监控。通过实际项目案例(如电商订单系统),帮助开发者掌握 从单体应用迁移到高可用微服务系统的完整流程与实战能力。

113

2025.12.24

cookie
cookie

Cookie 是一种在用户计算机上存储小型文本文件的技术,用于在用户与网站进行交互时收集和存储有关用户的信息。当用户访问一个网站时,网站会将一个包含特定信息的 Cookie 文件发送到用户的浏览器,浏览器会将该 Cookie 存储在用户的计算机上。之后,当用户再次访问该网站时,浏览器会向服务器发送 Cookie,服务器可以根据 Cookie 中的信息来识别用户、跟踪用户行为等。

6415

2023.06.30

document.cookie获取不到怎么解决
document.cookie获取不到怎么解决

document.cookie获取不到的解决办法:1、浏览器的隐私设置;2、Same-origin policy;3、HTTPOnly Cookie;4、JavaScript代码错误;5、Cookie不存在或过期等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

340

2023.11.23

Java 项目构建与依赖管理(Maven / Gradle)
Java 项目构建与依赖管理(Maven / Gradle)

本专题系统讲解 Java 项目构建与依赖管理的完整体系,重点覆盖 Maven 与 Gradle 的核心概念、项目生命周期、依赖冲突解决、多模块项目管理、构建加速与版本发布规范。通过真实项目结构示例,帮助学习者掌握 从零搭建、维护到发布 Java 工程的标准化流程,提升在实际团队开发中的工程能力与协作效率。

3

2026.01.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.5万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.1万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号