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

最新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攻防实战 - 从原理到防护的最佳实践

回顾链接:
最新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在安全控制中的高阶魔法

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

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 发起转账请求 --><imgsrc="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,攻击者无法同步两个值。

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

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

4. 实战代码示例

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

4.1 在 Spring Security 中启用 CSRF 防护

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

❶ Thymeleaf 模板中集成

@Configuration@EnableWebSecuritypublicclassSecurityConfig{@BeanpublicSecurityFilterChainfilterChain(HttpSecurity http)throwsException{ http .csrf(csrf -> csrf // 可自定义 CsrfTokenRepository,例如 CookieCsrfTokenRepository.withHttpOnlyFalse()).authorizeHttpRequests(auth -> auth .anyRequest().authenticated()).formLogin(withDefaults());return http.build();}}

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

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

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

❷ 前后端分离适配方案

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

// 自定义CSRF令牌处理器publicclassSpaCsrfTokenRequestHandlerextendsCsrfTokenRequestAttributeHandler{@Overridepublicvoidhandle(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@EnableWebSecuritypublicclassSecurityConfig{@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{ http .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).csrfTokenRequestHandler(newSpaCsrfTokenRequestHandler()))// 其他配置...return http.build();}}

❸ 自定义令牌存储策略

// 使用Redis存储CSRF令牌(分布式场景)@BeanpublicCsrfTokenRepositoryredisCsrfTokenRepository(RedisTemplate<String,String> redisTemplate){returnnewCsrfTokenRepository(){@OverridepublicCsrfTokengenerateToken(HttpServletRequest request){returnnewDefaultCsrfToken("X-CSRF-TOKEN","_csrf", UUID.randomUUID().toString());}@OverridepublicvoidsaveToken(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);}}@OverridepublicCsrfTokenloadToken(HttpServletRequest request){String sessionId = request.getSession().getId();String token = redisTemplate.opsForValue().get(sessionId);return token !=null?newDefaultCsrfToken("X-CSRF-TOKEN","_csrf", token):null;}};}

前端演示代码

// 初始化时获取CSRF Tokenfetch('/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验证

publicclassDoubleCookieCsrfFilterextendsOncePerRequestFilter{@OverrideprotectedvoiddoFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain)throwsServletException,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);}privatebooleanrequiresValidation(HttpServletRequest request){return"POST".equalsIgnoreCase(request.getMethod())||"PUT".equalsIgnoreCase(request.getMethod())||"DELETE".equalsIgnoreCase(request.getMethod());}}

4.3 SameSite Cookie策略

限制cookie的跨站请求

@BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurity http)throwsException{ http .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).csrfTokenRequestHandler(newCsrfTokenRequestAttributeHandler())).sessionManagement(session -> session .sessionCookiePolicy(cookie -> cookie.sameSite(SameSite.STRICT)));return http.build();}

结语

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

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


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

Read more

Flutter for OpenHarmony:web_socket_channel 全平台 WebSocket 通信标准库,从原理到鸿蒙实战(3000字深度解析)

Flutter for OpenHarmony:web_socket_channel 全平台 WebSocket 通信标准库,从原理到鸿蒙实战(3000字深度解析)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在现代 App 开发中,实时通信(Real-time Communication)已成为标配。无论是社交聊天的由“推”变“拉”,还是股票行情的毫秒级跳动,亦或是智能家居的状态同步,传统的 HTTP 轮询(Polling)已无法满足低延迟、高并发的需求。 WebSocket 协议应运而生。它基于 TCP,但在握手阶段利用 HTTP 升级协议(Upgrade Header),成功后建立全双工(Full-Duplex)的长连接。在这条通道上,客户端和服务端可以随时互相推送数据,且头部开销极小。 在 Flutter 生态中,虽然 dart:io 提供了原生的 WebSocket 类,dart:

By Ne0inhk
【面试分享】前端 React 50个基础高频面试题,助你轻松拿 offer!

【面试分享】前端 React 50个基础高频面试题,助你轻松拿 offer!

目录 前端基础高频面试题之-- React 篇 1、什么是React? 2、React有什么特点? 3、列出React的一些主要优点。 4、React有哪些限制? 5、什么是JSX? 6、为什么浏览器无法读取JSX? 7、React中的组件是什么? 8、怎样解释 React 中 render() 的目的。 9、什么是 Props? 10、React中的状态是什么?它是如何使用的? 11、 React 中的箭头函数是什么?使用箭头函数的好处? 12、什么是高阶组件(HOC)? 13、你能用HOC做什么? 14、什么是纯组件? 16、什么是React 路由? 17、为什么 useState 返回的是数组而不是对象? 18、如何实现

By Ne0inhk
【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题 在开发 Web 应用时,尤其是集成了 Unity WebGL 内容的页面,遇到一个问题:当 Unity WebGL 渲染内容嵌入到一个 Tab 中时,切换 Tab 后画面会变黑,直到用户点击黑屏区域,才会恢复显示。 这个问题通常是因为 Unity 渲染在 Tab 切换时被暂停或未能获得焦点所致。 在本文中,我们将介绍如何在使用 Layui 框架时,通过监听 Tab 切换事件并强制 Unity WebGL 渲染恢复,来解决这一问题。 1. 问题描述 当 Unity WebGL 内容嵌入到页面中的多个

By Ne0inhk

OpenClaw Web Search 完全指南(2026年3月最新)

OpenClaw Web Search 完全指南(2026年3月最新) 本文详细介绍 OpenClaw 内置 web_search 工具的 5 个官方搜索渠道,以及 Tavily 技能的使用方法。帮助你选择最适合的免费/付费方案。 目录 * OpenClaw 搜索功能概述 * 5 个官方搜索渠道详解 * 1. Brave Search API * 2. Google Gemini * 3. Grok (xAI) * 4. Kimi (Moonshot) * 5. Perplexity * 免费额度对比表 * 推荐配置方案 * Tavily Web Search 技能 * 配置步骤详解 * 常见问题 OpenClaw 搜索功能概述 OpenClaw 提供两种搜索能力:

By Ne0inhk