欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践

最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践

2025/4/18 18:29:24 来源:https://blog.csdn.net/lhmyy521125/article/details/147314076  浏览:    关键词:最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践

在这里插入图片描述

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
🌞《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践

  • 1. 前言
  • 2. CSRF 攻击原理
    • 2.1 攻击原理图解
    • 2.2 攻击示例
  • 3. Spring Security防御机制解析
    • 3. 1 同步令牌模式(Synchronizer Token Pattern)
    • 3. 2 双重提交 Cookie(Double Submit Cookie)
    • 3. 3 SameSite Cookie 属性
  • 4. 实战代码示例
    • 4.1 在 Spring Security 中启用 CSRF 防护
      • ❶ Thymeleaf 模板中集成
      • ❷ 前后端分离适配方案
      • ❸ 自定义令牌存储策略
    • 4.2 双重Cookie验证
    • 4.3 SameSite Cookie策略
  • 结语

回顾链接:
最新Spring Security实战教程(一)初识Spring Security安全框架
最新Spring Security实战教程(二)表单登录定制到处理逻辑的深度改造
最新Spring Security实战教程(三)Spring Security 的底层原理解析
最新Spring Security实战教程(四)基于内存的用户认证
最新Spring Security实战教程(五)基于数据库的动态用户认证传统RBAC角色模型实战开发
最新Spring Security实战教程(六)最新Spring Security实战教程(六)基于数据库的ABAC属性权限模型实战开发
最新Spring Security实战教程(七)方法级安全控制@PreAuthorize注解的灵活运用
最新Spring Security实战教程(八)Remember-Me实现原理 - 持久化令牌与安全存储方案
最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合
最新Spring Security实战教程(十)权限表达式进阶 - 在SpEL在安全控制中的高阶魔法

专栏更新完毕后,博主将会上传所有章节代码到CSDN资源免费给大家下载,如你不想等后续章节代码需提前获取,可以私信或留言!

1. 前言

在前面学习的章节中,相信大家一定看一个配置 .csrf() , 回忆一下之前使用 Spring Security 默认页登录的时候,该配置 Spring Security 默认开启,主要做用于 CSRF 防护, 如果你现在还不了解什么是 CSRF 防护,没关系通过本章节,博主带着大家一起深入学习这个知识点~


2. CSRF 攻击原理

跨站请求伪造(CSRF)是一种利用受信任用户的身份,诱使用户在已登录的应用中执行非预期操作的攻击手段。

当用户在某个站点(如银行)登录并持有有效 Session Cookie 后,攻击者可通过精心构造的请求(例如隐藏在图片或表单中的 POST 请求)在用户不知情的情况下向该站点发起请求,并携带用户的 Cookie,从而完成诸如转账、修改邮箱等敏感操作。

2.1 攻击原理图解

用户访问了A站点,获得了Session或Cookie后,
用户不经意间访问到了恶意网站,此刻恶意网站伪造对A站点的危险请求

在这里插入图片描述

2.2 攻击示例

下面示例展示了一个最常见的 CSRF 攻击场景:用户登录了 https://bank.com 后,攻击者在自己的网站 https://evil.com 上放置如下 HTML 片段:

<!-- 在恶意页面上渲染时,立即向 bank.com 发起转账请求 -->
<img src="https://bank.com/transfer?amount=1000&to=attacker" />

3. Spring Security防御机制解析

3. 1 同步令牌模式(Synchronizer Token Pattern)

同步令牌模式是 Spring Security 的默认方案, 服务器在渲染每个需要保护的表单页面时,向用户 Session 中存入一个随机生成的 Token,并在表单中以隐藏字段输出;提交时,服务器验证该字段与 Session 中的 Token 是否一致,若不匹配则拒绝请求。此模式能有效防止 CSRF 攻击,因为攻击者无法从第三方域读取到该随机 Token

核心防御流程
在这里插入图片描述

  • 服务端生成随机Token(每个Session唯一)
  • Token嵌入HTML表单的隐藏字段或HTTP头
  • 客户端提交请求时必须携带有效Token
  • 服务端校验Token合法性

3. 2 双重提交 Cookie(Double Submit Cookie)

服务器在首次响应页面时,通过 Set-Cookie 设置一个随机 Token,同时在页面中通过脚本将该 Token 读出并写入一个请求头(或隐藏表单字段)。服务器接收请求后,比较 Cookie 中的 Token 与请求中携带的 Token 是否一致。由于浏览器同源策略不能让第三方域读取 Cookie,攻击者无法同步两个值。

3. 3 SameSite Cookie 属性

浏览器支持在 Set-Cookie 响应头中声明 SameSite 属性,用来限制 Cookie 在跨站请求时是否发送。设置为 Strict 或 Lax 模式,可从源头上阻止大部分 CSRF 请求

  • SameSite=Strict:绝不在第三方请求中发送该 Cookie;
  • SameSite=Lax:仅允许在“安全”的跨站 GET 导航中发送。

4. 实战代码示例

这里我们将针对上述三种防护机制,进行相关代码演示

4.1 在 Spring Security 中启用 CSRF 防护

Spring Security 默认开启 CSRF 保护,采用的是同步令牌模式。下面展示如何单体、前后分离中集成

❶ Thymeleaf 模板中集成

@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.csrf(csrf -> csrf// 可自定义 CsrfTokenRepository,例如 CookieCsrfTokenRepository.withHttpOnlyFalse()).authorizeHttpRequests(auth -> auth.anyRequest().authenticated()).formLogin(withDefaults());return http.build();}
}

在 Thymeleaf 页面中添加隐藏字段,设置Token

<!-- Thymeleaf 模板:form.html -->
<form th:action="@{/transfer}" method="post"><!-- 输出 CSRF 隐藏字段 --><input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /><input type="number" name="amount" /><button type="submit">Transfer</button>
</form>

在控制器中,Spring Security 自动会在每次 POST 请求时校验表单中的 ${_csrf.token}Session 中的令牌是否匹配,
不匹配则抛出InvalidCsrfTokenException

❷ 前后端分离适配方案

下面演示在前后分离中的适配,前端在请求前 初始化时获取CSRF Token

// 自定义CSRF令牌处理器
public class SpaCsrfTokenRequestHandler extends CsrfTokenRequestAttributeHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {// 将CSRF Token暴露给前端JavaScriptCsrfToken token = csrfToken.get();if (token != null) {response.setHeader(token.getHeaderName(), token.getToken());}}
}//SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()))// 其他配置...return http.build();}
}

❸ 自定义令牌存储策略

// 使用Redis存储CSRF令牌(分布式场景)
@Bean
public CsrfTokenRepository redisCsrfTokenRepository(RedisTemplate<String, String> redisTemplate) {return new CsrfTokenRepository() {@Overridepublic CsrfToken generateToken(HttpServletRequest request) {return new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", UUID.randomUUID().toString());}@Overridepublic void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {String sessionId = request.getSession().getId();if (token == null) {redisTemplate.delete(sessionId);} else {redisTemplate.opsForValue().set(sessionId, token.getToken(), 30, MINUTES);}}@Overridepublic CsrfToken loadToken(HttpServletRequest request) {String sessionId = request.getSession().getId();String token = redisTemplate.opsForValue().get(sessionId);return token != null ? new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", token) : null;}};
}

前端演示代码

// 初始化时获取CSRF Token
fetch('/csrf', { credentials: 'include' }).then(res => {const token = res.headers.get('X-CSRF-TOKEN');axios.defaults.headers.common['X-CSRF-TOKEN'] = token;});// 所有POST请求自动携带Token
axios.interceptors.request.use(config => {if (['post', 'put', 'delete'].includes(config.method.toLowerCase())) {config.headers['X-CSRF-TOKEN'] = getCSRFToken(); }return config;
});

4.2 双重Cookie验证

实际上在我们日常开发中,使用 Spring Security 同步令牌方案,基本能满足我们大部分需求,这里就简单演示一下双重Cookie验证

public class DoubleCookieCsrfFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());if (requiresValidation(request)) {String headerToken = request.getHeader(token.getHeaderName());String cookieToken = getCookieValue(request, "CSRF-TOKEN");if (!token.getToken().equals(headerToken) || !token.getToken().equals(cookieToken)) {response.sendError(HttpStatus.FORBIDDEN.value());return;}}filterChain.doFilter(request, response);}private boolean requiresValidation(HttpServletRequest request) {return "POST".equalsIgnoreCase(request.getMethod()) ||"PUT".equalsIgnoreCase(request.getMethod()) ||"DELETE".equalsIgnoreCase(request.getMethod());}
}

4.3 SameSite Cookie策略

限制cookie的跨站请求

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())).sessionManagement(session -> session.sessionCookiePolicy(cookie -> cookie.sameSite(SameSite.STRICT)));return http.build();
}

结语

CSRF 攻击凭借“利用用户身份” 的特点,对任何依赖 Cookie 的状态修改接口都构成威胁。本文从攻击原理入手,详细介绍了同步令牌双重提交 CookieSameSite 属性等防护方案,并给出了对应代码供小伙伴们参考!

希望这个章节的内容能够帮助小伙伴们更深入地理解 CSRF 的知识,在实际项目中设计出更灵活高效的安全策略。如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!


下一章节:最新Spring Security实战教程(十二)CORS安全配置 - 跨域请求的安全边界设定

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词