阶段一:SpringSecurity 项目安全基石

📅 2026/7/3 4:54:02
阶段一:SpringSecurity 项目安全基石
认证验证用户身份比如账号密码是否正确决定“谁能进入系统”授权控制用户可访问的资源比如普通用户不能访问管理员页面决定“进入系统后能做什么”攻击防护自带主流Web攻击防护机制避免系统被恶意攻击。回到顶部1、典型Web安全漏洞1、XSS跨站脚本1、核心原理系统未对用户输入的内容做HTML 特殊字符过滤 / 转义允许恶意 JS/HTML 代码提交并持久化存储如数据库、缓存当其他用户访问包含该恶意内容的页面时前端浏览器会将恶意代码当作正常页面代码解析并自动执行黑客借此窃取用户 Cookie、冒充用户操作或篡改页面内容。核心本质是把不可信的用户输入当作可信的页面代码执行。2、典型场景电商平台商品评论区、社交平台留言框、论坛发帖区、后台管理系统反馈模块支持用户输入文本的公共 / 私密模块均适用。3、流程化攻击步骤黑客在电商评论区提交评论内容为scriptvar cookie document.cookie; 发送数据到黑客服务器(cookie);/script电商系统未做任何处理直接将该恶意代码存入数据库普通用户打开该商品详情页系统从数据库读取评论并直接渲染到页面普通用户的浏览器解析并执行评论中的恶意 JS自动将用户的登录 Cookie 发送到黑客服务器黑客获取 Cookie 后冒充该普通用户登录电商平台查看订单、修改收货地址等。2、CSRF跨站请求伪造1、核心原理用户在目标系统登录后浏览器会保留有效的会话凭证Session/Cookie 且未过期黑客利用浏览器的 “自动携带同域 Cookie” 特性搭建恶意页面并诱导用户访问恶意页面会向目标系统发起跨域伪造请求如改密码、转账目标系统仅通过 Cookie 验证用户登录状态未校验请求是否为用户主动 / 自愿发起误将伪造请求当作用户本人操作执行。核心本质是利用有效会话 无请求合法性校验冒充用户发起非自愿操作。2、典型场景银行/支付平台转账、电商平台修改收货地址/确认下单、任意系统修改密码/绑定手机号、后台管理系统删除数据需登录后执行的写操作均适用。3、流程化攻击步骤用户打开招商银行官网输入账号密码登录浏览器保存招行的登录 Cookie未退出、未过期用户未关闭浏览器无意间点击了黑客发送的 “免费领取话费” 链接跳转到黑客搭建的恶意页面恶意页面加载后自动向招行后台发起 POST 请求https://cmb.com/transfer?to黑客账号money5000浏览器会自动携带招行的登录 Cookie招行后台仅校验 Cookie 是否有效发现用户已登录未做其他验证直接执行转账操作用户银行卡被转走 5000 元全程无感知未主动操作过转账。3、会话固定1、核心原理目标系统存在**“未登录即可生成有效 SessionID”**且**“用户登录后不更换 SessionID”**的双重问题黑客先访问目标系统获取一个合法的 SessionID通过链接、二维码等方式诱骗用户使用该 SessionID 访问系统并完成登录由于登录前后 SessionID 未变黑客持有的该 SessionID 会被绑定到用户的登录状态后续黑客直接使用该 SessionID 即可冒充用户登录系统获取用户权限。核心本质是登录不更换 SessionID导致黑客提前获取的无效 SessionID 被绑定为有效登录凭证。2、典型场景所有基于 Session 做登录状态管理的 Web 系统尤其是未做 Session 安全配置的系统如电商、管理后台、社交平台。3、流程化攻击步骤黑客先访问某电商平台无需登录平台为其生成合法 SessionIDJSESSIONID123456黑客保存该 ID黑客将带该 SessionID 的链接发给用户https://shop.com?JSESSIONID123456用户点击该链接访问电商平台输入自己的账号密码完成登录电商平台未更换 SessionID仍使用123456并将该 ID 绑定到用户的登录状态黑客在自己的浏览器中设置 Cookie 为JSESSIONID123456访问电商平台直接以该用户身份登录可查看订单、修改信息。除此之外Web开发中还有诸多典型高危安全漏洞比如同权限用户间可通过修改请求 ID 访问他人数据的水平越权、低权限用户可直接访问高权限接口执行高危操作的垂直越权利用页面嵌套和视觉欺骗诱导用户非自愿操作的点击劫持密码在网络传输或数据库存储中未做安全加密易被窃取的密码明文传输/弱存储敏感接口未做任何认证授权校验可被匿名访问的未授权访问以及黑客通过窃取有效 SessionID 冒充用户登录的会话劫持这些漏洞均因系统在权限校验、数据防护、会话管理、页面安全等方面的配置或逻辑缺失引发是 Web 安全防护中需重点关注的要点。回到顶部2、常见认证方式认证方式核心原理典型特点/实现适用场景账号密码认证含HTTP BASIC用户输入账号密码服务端校验与存储的加密密码是否一致最基础的认证思路HTTP BASIC是其 HTTP 协议原生实现账号密码经 Base64 编码放入请求头所有系统基础登录、内部低安全需求简单服务Session-Cookie认证账号密码校验通过后服务端生成 SessionID 并存储用户登录状态客户端通过 Cookie 保存 SessionID后续请求自动携带完成身份识别服务端有状态需存储会话信息Spring Security默认认证方式适配HTTP无状态特性传统单体 Web 项目SSM/SSH 架构TokenJWT认证账号密码校验通过后服务端生成加密令牌返回客户端后续请求携带令牌完成校验服务端无需存储令牌及用户状态服务端无状态主流实现为 JWT可自定义携带用户基础信息、设置过期时间令牌通常存请求头/客户端本地存储前后端分离项目、微服务架构、移动端 APP / 小程序API密钥认证AppKey/AppSecret为调用方分配唯一 AppKey公开身份标识AppSecret私密签名密钥请求时通过密钥对请求签名服务端验签通过即完成认证双密钥机制无令牌生成流程使用固定密钥做请求签名服务端需存储密钥对用于验签服务间调用、开放平台API、第三方系统对接、内部微服务通信OAuth2.0第三方授权认证基于OAuth2.0协议通过微信/支付宝/QQ等第三方已认证的账号完成授权获取用户唯一标识即可实现登录免注册快捷登录无需自身系统管理用户账号密码衍生OpenID Connect协议增强身份认证能力C端产品、大众端应用、小程序、各类社交/电商APP快捷登录回到顶部3、相关框架框架核心优势主要不足适用场景Spring SecuritySpring生态原生无缝集成Spring Boot/Cloud自动配置开箱即用原生内置OAuth2.0、SSO、CSRF/CORS防护等企业级功能天生适配微服务无状态设计支持URL/方法/数据级细粒度权限控制学习成本高配置细节繁琐非Spring生态项目适配性差轻量项目使用有功能冗余Spring Boot/Cloud微服务架构、企业级复杂系统、金融/政务等高安全需求场景、需原生SSO/第三方授权的项目Apache Shiro轻量易用学习/配置成本极低跨框架通用无依赖支持Spring/JavaSE等组件解耦度高自定义扩展简单无侵入高级功能OAuth2.0/SSO需集成第三方组件无原生微服务/分布式支持需手动改造仅原生支持URL/方法级授权数据级需自定义单体Web项目、中小规模系统、非Spring生态跨框架项目、快速开发上线的常规认证授权需求场景Sa-Token国产轻量安全框架极简 API、零配置开箱即用原生支持微服务分布式、单点登录 SSO、OAuth2.0、 jwt、无感刷新、同端互斥登录适配 Spring Boot/Cloud适配性极强上手成本远低于前两者内置防重放、防爬虫、账号封禁、二级认证等常用功能行业老牌大厂标准化落地案例少于 Spring Security小众技术栈适配生态稍弱超大型复杂权限模型不如 Security 原生灵活中小型微服务、创业项目、快速开发项目、不想啃复杂配置的 Spring 项目、需要快速落地 SSO/OAuth2 又不想折腾整合的项目回到顶部二、Spring Security 6 快速入门回到顶部1、项目结构环境/工具版本要求说明JDKJava 17Spring 6 最低要求 Java 17Java 8/11 无法兼容回到顶部2、引入依赖!-- Spring 6 最低要求 Java 17-- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency回到顶部3、创建控制器RestController RequestMapping(v1) public class BasicController { /** * http://localhost:8080/v1/hello * * return */ GetMapping(/hello) public String hello() { return Hello SpringSecurity6; } }回到顶部4、访问资源引入 spring-boot-starter-security 依赖后Spring Security 会基于 Spring Boot 自动配置机制默认生效全局拦截所有匹配 /** 路径的 HTTP 请求当未认证用户访问受保护资源时框架将自动重定向至其内置的 GET /login 登录页面完成身份认证。发起请求-跳转到框架内置的登录页面http://localhost:8080/v1/hello默认用户名user密码项目启动时控制台打印的随机UUID回到顶部5、自定义登录用户、密码与角色Spring Security 默认提供的 user 用户名 随机密码临时用户体系仅适用于开发阶段的快速验证场景无法满足实际业务中自定义身份凭证、密码加密存储、角色权限分配等核心需求。为此我们提供两种自定义登录用户、密码及角色的实现方案两种方案适用场景不同且配置优先级明确Java 配置类优先级高于 YAML 配置。1、方式一基于 YAML 配置文件自定义该方案无需编写 Java 配置类仅通过配置文件即可快速自定义默认用户的账号、密码与角色适用于本地开发快速测试场景。1、核心局限性仅支持单用户配置、密码仅能以明文形式存储、无法实现角色与资源的精细化权限管控不支持对接数据库等持久化存储方案仅可作为临时测试手段严禁用于生产环境。2、配置示例spring: security: user: # 自定义用户名 name: admin # 自定义密码 password: 123456 # 自定义用户角色仅支持给单用户配置多角色用英文逗号分隔如ADMIN,USER roles: ADMIN3、测试接口示例开启方法级权限校验EnableMethodSecurity编写测试接口验证用户登录状态与角色权限EnableMethodSecurity RestController RequestMapping(v2) public class BasicYmlController { // 无需角色仅需登录即可访问验证用户登录是否生效 GetMapping(/hello) public String hello() { return 登录成功当前访问的是通用接口; } // 仅ADMIN角色可访问验证角色配置是否生效 PreAuthorize(hasRole(ADMIN)) GetMapping(/admin/hello) public String adminHello() { return 登录成功当前访问的是ADMIN角色专属接口; } // 仅USER角色可访问验证角色配置是否生效 PreAuthorize(hasRole(USER)) GetMapping(/user/hello) public String userHello() { return 登录成功当前访问的是USER角色专属接口; } }2、方式二基于配置类 Bean 自定义YAML 配置的局限性无法满足生产环境的安全规范与业务复杂度要求基于 Java 配置类 Bean 的实现方案是生产环境标准方案。该方案完全弥补了 YAML 配置的短板支持密码加密、多用户多角色配置、角色与资源精细化权限绑定等核心能力同时配置优先级更高若两种配置方式同时启用YAML 配置的用户信息会被直接覆盖失效。1、核心配置类import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; /** * Spring Security 6 核心配置类 * * Configuration标识该类是Spring配置类Spring启动时自动加载该类的所有配置 * EnableWebSecurity启用Spring Security的Web安全功能必须添加否则Security不生效 */ Configuration EnableWebSecurity public class SecurityConfig { /** * 1. 密码编码器Spring Security 6 必须指定否则启动报错 * 作用对用户密码进行加密存储避免明文存储明文存储存在极大安全隐患 * * BCryptPasswordEncoderSpring官方推荐的密码加密方式不可逆安全性高 * 特点相同明文密码每次加密后的结果都不同自带随机盐值 * Bean将该方法的返回值密码编码器交给Spring容器管理后续其他地方可直接注入使用 */ Bean public PasswordEncoder passwordEncoder() { // 返回BCrypt密码编码器实例后续所有密码加密、校验都用该编码器 return new BCryptPasswordEncoder(); } /** * 2. 基于内存的用户信息 * 作用模拟用户数据用于测试认证、授权功能 * * UserDetailsServiceSpring Security提供的接口用于加载用户信息用户名、密码、角色 * 本阶段创建2个测试用户用于验证角色权限 * - 普通用户usernameuserpassword123456角色USER只能访问普通接口 * - 管理员用户usernameadminpassword123456角色ADMIN可访问所有接口 */ Bean public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { // 普通用户角色USER // 设置用户名 UserDetails user User.withUsername(user) // 密码必须加密使用上面定义的密码编码器对明文密码123456进行加密 // 注意Spring Security 6 禁止明文密码必须加密否则登录失败 // {noop} 的含义No Operation Password Encoder表示不对密码进行任何加密处理 // .password({noop}123456) .password(passwordEncoder.encode(123456)) // 方式一配置用户资源访问权限 // .authorities(USER_RESOURCE) // 方式二配置用户角色Spring会自动给角色添加前缀 ROLE_数据库存储时无需加 .roles(USER) // 构建用户对象 .build(); // 管理员用户角色ADMIN UserDetails admin User.withUsername(admin) .password(passwordEncoder.encode(123456)) // .authorities(ADMIN_RESOURCE) .roles(ADMIN) .build(); // 将用户信息存入内存返回内存级别的用户详情服务后续替换为数据库查询 return new InMemoryUserDetailsManager(user, admin); } /** * 3. 安全过滤链核心配置接口权限、登录登出行为 * 作用拦截所有HTTP请求根据配置的规则校验请求的权限是否需要登录、是否有对应角色 * * HttpSecurity用于配置安全规则接口权限、登录页、登出逻辑等 * SecurityFilterChainSpring Security 6 新API用于封装所有安全过滤规则返回后生效 */ Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // 配置HTTP请求的安全规则链式编程配置完成后返回SecurityFilterChain实例 http // 关闭CSRF防护 // CSRF跨站请求伪造防护关闭后可避免前端调用接口时报403错误 .csrf(csrf - csrf.disable()) // 配置接口访问权限规则核心控制哪些接口能访问、哪些需要认证/角色 .authorizeHttpRequests(auth - auth // 1. 匿名可访问接口/v3/hello无需登录任何人都能访问 // /loginSpring Security默认登录页地址必须允许匿名访问否则未登录无法访问登录页 .requestMatchers(/v3/hello, /login).permitAll() // 2. 需指定角色可访问接口所有以 /v3/admin/ 开头的接口必须拥有ADMIN角色 //.requestMatchers(/v3/admin/**).hasAuthority(ADMIN_RESOURCE) // 对应配置.authorities(ADMIN_RESOURCE) .requestMatchers(/v3/admin/**).hasRole(ADMIN) // 3. 其他所有接口必须登录认证无论什么角色后才能访问 .anyRequest().authenticated() ) // 方式一自定义配置登录成功/失败处理器返回JSON格式认证结果 // .formLogin(form - form // .successHandler((request, response, authentication) - { // response.setContentType(application/json;charsetUTF-8); // response.getWriter().write({\code\:200,\message\:\登录成功\}); // }) // .failureHandler((request, response, exception) - { // response.setContentType(application/json;charsetUTF-8); // response.setStatus(401); // response.getWriter().write({\code\:401,\message\:\登录失败\}); // }) // ) // 方式二使用默认表单登录配置 .formLogin(Customizer.withDefaults()) // 使用默认登出配置 .logout(Customizer.withDefaults()); return http.build(); } }注加密实现类核心特点适用场景优缺点BCryptPasswordEncoder基于 BCrypt 哈希算法自动生成随机盐值无需手动管理盐不可逆加密计算慢抗暴力破解99%的生产场景Web 应用、微服务、企业系统优点安全、自带盐值、Spring 官方推荐缺点计算速度慢但这也是安全的体现SCryptPasswordEncoder基于 SCrypt 算法比 BCrypt 更安全内存密集型抗 ASIC/GPU 破解同样自动生成盐值高安全要求场景金融、政务、支付系统优点安全性高于 BCrypt缺点计算 / 内存消耗更大普通系统没必要Pbkdf2PasswordEncoder基于 PBKDF2 算法符合 NIST美国国家标准与技术研究院规范自动加盐需符合特定合规要求的场景如政府 / 金融行业合规优点合规性强缺点安全性略低于 BCrypt/SCryptArgon2PasswordEncoder基于 Argon2 算法2015 年密码哈希竞赛冠军内存 CPU 密集型抗破解能力最强超高安全要求场景如密码管理器、区块链钱包优点目前最安全的哈希算法缺点JDK11 才支持资源消耗大NoOpPasswordEncoder无加密明文存储仅兼容旧系统已标记为 Deprecated废弃仅本地测试绝对禁止生产优点测试方便缺点完全不安全生产用会直接泄露密码MessageDigestPasswordEncoder基于 MD5/SHA-1 等哈希算法无盐 / 固定盐仅兼容极老旧系统如遗留项目优点兼容旧系统缺点无盐值易被彩虹表破解已淘汰盐值随机字符串作用是和密码混合加密避免相同密码生成相同密文2、测试接口示例RestController RequestMapping(v3) public class BasicBeanController { /** * 1. 匿名可访问接口无需登录任何人都能访问 */ GetMapping(/hello) public String hello() { return Hello您无需登录任何人都能访问匿名访问接口; } /** * 2. 需登录认证接口必须登录无论什么角色登录即可访问 * 未登录访问会自动跳转到 Spring Security 默认登录页 * 登录后访问返回正常响应内容 */ GetMapping(/user/info) public String userInfo() { return Hello, User! 你已成功登录可访问该需认证接口; } /** * 3. 需指定角色接口必须登录且登录用户拥有 ADMIN 角色否则无权访问 * 普通用户登录访问返回 403 Forbidden无权访问 * 管理员用户登录访问返回正常响应内容 */ GetMapping(/admin/info) public String adminInfo() { return Hello, Admin! 你是管理员ADMIN角色可访问该权限接口; } }回到顶部三、Spring Security 6 的相关过滤器链Spring Security 6 的 Web 安全基于Servlet 过滤器链实现核心由FilterChainProxy核心代理与SecurityFilterChain具体安全链组成形成 “单代理多链” 的灵活架构。FilterChainProxy全局唯一的 Servlet Filter注册名为springSecurityFilterChain负责分发请求到匹配的 SecurityFilterChainSecurityFilterChain多条独立安全链按order排序每条包含RequestMatcher请求匹配规则 过滤器列表仅匹配请求才会进入对应链SpringFilterOrderSpring Security 6 通过SecurityFilterOrder枚举严格定义过滤器执行顺序确保依赖关系正确