Spring Security会话管理与CSRF详解

Spring Security会话管理与CSRF详解

定位:第 04 篇,讲透会话形态与认证状态管理、会话固定攻击防护、并发会话控制与 CSRF 防护机制

适用版本:Spring Security 6.x(Spring Boot 3.x)


目录


一、会话与认证状态

1.1 两种会话形态

形态 机制 典型场景
有状态 登录后 SecurityContext 存入 HttpSession,后续请求靠会话恢复 表单登录的 Web 应用
无状态 不用会话,每次请求携带凭证(JWT),服务端现验 前后端分离、微服务 API
java 复制代码
// 无状态会话策略(JWT API 标配)
http.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

1.2 会话策略枚举

策略 行为
ALWAYS 总是创建会话
IF_REQUIRED 需要时创建(默认)
NEVER 不主动创建,存在则用
STATELESS 完全不使用会话

1.3 并发会话控制

java 复制代码
http.sessionManagement(s -> s.maximumSessions(1)      // 每账号最多 1 个会话
        .maxSessionsPreventsLogin(false));            // 新登录踢掉旧会话

依赖 SessionRegistry 跟踪所有会话;集群环境需共享会话(Redis,Session 主题)才能全局生效。


二、会话固定攻击

2.1 攻击原理

复制代码
① 攻击者先访问站点拿到一个 sessionId
② 诱导受害者用该 sessionId 登录(如 URL 带 session 参数)
③ 受害者登录后,攻击者用同一 sessionId 直接获得其会话

2.2 防护:登录换 ID

复制代码
默认策略 migrateSession:
   登录成功 → 作废旧 sessionId、生成新的、迁移会话数据
   → 攻击者手里的旧 ID 失效

其他策略:changeSessionId(容器层换 ID)、newSession(全新会话,更彻底)。默认配置已防护,不要随意关闭。


三、CSRF

3.1 攻击原理

复制代码
前提:用户已登录站点 A(浏览器持有 A 的 Cookie)
① 用户访问恶意站点 B
② B 页面发起对 A 的请求(表单自动提交)
③ 浏览器自动携带 A 的 Cookie → A 以为是用户本人操作

利用的是"浏览器自动携带 Cookie "与"服务端只凭 Cookie 认身份"。

3.2 防护:CSRF Token

复制代码
① 服务端生成随机 Token,绑定会话,渲染进表单(隐藏域)/下发给前端
② 状态变更请求(POST/PUT/DELETE)必须携带 Token(表单域或 X-CSRF-TOKEN 头)
③ CsrfFilter 校验:无 Token 或不匹配 → 403
④ 只读请求(GET/HEAD/OPTIONS)豁免

恶意站点无法跨站读到 Token(同源策略),所以伪造请求带不上合法 Token。

3.3 豁免场景

复制代码
无状态 API(JWT/OAuth2 Bearer 认证):身份不靠 Cookie,CSRF 不成立 → 通常禁用
   http.csrf(csrf -> csrf.disable())     // 仅限无状态
混合:只对状态变更的会话路径开启,/api/** 豁免

纪律:有状态(Cookie 会话)应用不要关 CSRF;无状态才关,且确保认证确实不依赖 Cookie。

3.4 纵深防护:SameSite

Cookie 的 SameSite=Lax/Strict 让浏览器在跨站请求时不携带 Cookie------现代浏览器默认 Lax,已大幅缓解 CSRF。但它是浏览器行为、有兼容差异,不能替代 Token,只能叠加。


四、安全响应头

Security 默认为响应添加防护头:

头 作用
X-Content-Type-Options: nosniff 防 MIME 类型嗅探
X-Frame-Options: DENY 防点击劫持(禁止被 iframe 嵌套)
Cache-Control 敏感响应禁缓存
Content-Security-Policy 内容安全策略(需显式配置)
X-XSS-Protection 旧浏览器 XSS 过滤(已不推荐依赖)

默认开启是"安全默认值"的又一例;按需覆盖而非关闭。


五、总结

  1. 会话形态:有状态(会话存上下文)与无状态(STATELESS,JWT);按认证方式选择,混合场景分链配置。
  2. 会话固定:登录后更换 sessionId(默认 migrateSession)使被盗用的旧 ID 失效;不要关闭。
  3. 并发控制:maximumSessions + SessionRegistry;集群要共享会话才全局生效。
  4. CSRF:利用浏览器自动带 Cookie 冒名提交;防护是绑定会话的 Token,状态变更请求必带;无状态 API 才豁免;SameSite 是纵深补充不替代。
  5. 安全头:默认添加防嗅探/点击劫持等,按需配置 CSP。

六、常见高频面试题

1. 什么是会话固定攻击?Spring Security 怎么防?

要点:攻击者先拿到一个 sessionId 并诱导受害者用它登录,受害者登录后攻击者凭同一 sessionId 直接接管其会话。防护核心是登录成功后更换 sessionId------Security 默认 migrateSession 策略:登录时生成新 sessionId、迁移数据、旧 ID 作废,攻击者持有的旧 ID 失效。其他策略有 changeSessionId/newSession。该防护默认开启,不应关闭。

2. CSRF 攻击的原理是什么?

要点:利用"浏览器自动携带 Cookie"------用户已登录站点 A,访问恶意站点 B 时,B 诱导浏览器向 A 发起状态变更请求(如自动提交表单),浏览器自动带上 A 的 Cookie,A 无法区分这是伪造请求还是用户本人操作。成立条件:身份靠 Cookie、请求未验证来源。危害集中在写操作(转账、改设置),读操作一般无实质影响。

3. CSRF Token 是怎么工作的?

要点:服务端生成与用户会话绑定的随机 Token,下发给页面(表单隐藏域或元标签);所有状态变更请求(POST/PUT/DELETE)必须回传该 Token(表单域或 X-CSRF-TOKEN 头);CsrfFilter 校验 Token 与会话绑定关系,缺失或不匹配则 403。恶意站点因同源策略无法读到受害者页面上的 Token,伪造请求带不上合法 Token 而被拦截。GET 等只读方法豁免。

4. 前后端分离 + JWT 的项目,为什么要关闭 CSRF?

要点:CSRF 成立的前提是身份靠浏览器自动携带的 Cookie。JWT 方案里身份凭证是请求头中的 Token(不自动携带,攻击者拿不到也没法让浏览器自动带),CSRF 攻击不成立,所以通常禁用(配合 SessionCreationPolicy.STATELESS)。但注意:若同时仍用 Cookie 会话(如 OAuth2 登录后的会话),则不能关。是否关取决于认证机制是否依赖 Cookie,而非"是不是前后端分离"。

5. Spring Security 的会话创建策略有哪些?

要点:SessionCreationPolicy 四种------ALWAYS(总是创建)、IF_REQUIRED(需要时创建,默认)、NEVER(不主动创建,有则用)、STATELESS(完全不用会话,JWT API 标配)。选择与认证形态匹配:表单会话登录用默认;无状态 Token 认证用 STATELESS(同时常关 CSRF)。策略影响 SecurityContextRepository 是否持久化上下文。

6. 如何限制同一账号的并发登录?

要点:sessionManagement 配置 maximumSessions(1),配合 maxSessionsPreventsLogin 决定新登录是挤掉旧会话还是拒绝新登录。实现依赖 SessionRegistry 记录所有活跃会话与用户映射。注意:SessionRegistry 默认在单实例内存中------集群部署必须共享会话(如 Spring Session + Redis)才能真正全局限制并发会话。

7. SameSite Cookie 和 CSRF Token 什么关系?

要点:SameSite(Lax/Strict)让浏览器在跨站请求时不携带 Cookie,从源头削弱 CSRF(现代浏览器默认 Lax)。但它是浏览器行为:旧浏览器不支持、兼容模式可能失效、严格模式可能影响正常跨站跳转体验。所以 SameSite 是纵深防御层,不能替代服务端 CSRF Token------有状态应用两者叠加:Token 保证正确性,SameSite 减小攻击面。

8. SecurityContext 在会话模式下如何跨请求保持?

要点:登录成功后,SecurityContext(含 Authentication)由 SecurityContextRepository 保存到 HttpSession;后续请求进入时,安全上下文过滤器(6.x 的 SecurityContextHolderFilter 经仓库读取)从会话恢复上下文到 SecurityContextHolder,供授权使用;请求结束清理。这就是"登录一次、全程有效"的机制。无状态模式不保存,每次请求从 Token 重建。

9. Spring Security 默认设置了哪些安全响应头?

要点:常见的有 X-Content-Type-Options: nosniff(防 MIME 嗅探)、X-Frame-Options: DENY(防点击劫持)、Cache-Control(敏感响应禁缓存)、X-XSS-Protection(旧浏览器)。还可配置 Content-Security-Policy、HSTS(HTTPS 强制)等。默认开启体现安全默认值;按业务需要覆盖个别头(如允许特定站点 iframe),但应说明理由而非整体关闭。

10. 会话管理在集群环境下要注意什么?

要点:默认 HttpSession 存在单实例内存中,集群多实例时:① 会话不共享------请求打到别的实例就丢登录态(需粘性会话或会话共享);② 并发会话限制(SessionRegistry)、会话事件(登录/登出)只在单实例可见。解法:用 Spring Session + Redis 把会话外置共享(Session 主题深讲),实例无状态化,支持水平扩展与优雅停机不丢登录态。

相关推荐
Wx-bishekaifayuan1 小时前
springboot铜仁非遗之家76938-计算机课程设计、毕业设计
java·spring boot·后端·spring·django·课程设计·旅游
青春不朽5123 小时前
Python 里 a is b 有时 True 有时 False?小整数缓存和常量折叠的底层真相
python·spring·缓存
苏渡苇3 小时前
Spring Insight:跨服务调用链路是怎么串起来的?
spring boot·后端·spring·系统监控·apm
夕除4 小时前
redis--主从还是集群,内存
java·spring·mybatis
霸道流氓气质5 小时前
AI 简历制作平台:结构化输出解析、多模板渲染与 PDF 导出的 Vue3 + Spring AI 全栈实战
人工智能·spring·pdf
打工仔折腾 AI5 小时前
Spring AI + Qwen 周报生成实战:从原始日志到人工确认卡
人工智能·后端·python·spring·elasticsearch·ai agent 实战
开开心心就好5 小时前
手机电池健康怎么查?看容量温度循环次数
spring·智能手机·ffmpeg·计算机外设·电脑·maven·音视频
云和数据.ChenGuang5 小时前
Spring AI 对接 LangGraph:构建企业级智能体工作流实战
java·人工智能·spring boot·后端·spring
云和数据.ChenGuang5 小时前
Spring AI 入门实战:构建你的第一个 AI 应用
java·人工智能·深度学习·spring·机器学习·语言模型