当前位置: 首页 > news >正文

从0到1掌握 Spring Security(第四篇):密码加密原理、默认行为与配置选型

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

🎏:你只管努力,剩下的交给时间

🏠 :小破站

从0到1掌握 Spring Security(第四篇):密码加密原理、默认行为与配置选型

      • 摘要
    • 为什么必须“加密”(准确说是单向散列)?🧠
    • 默认行为(不配置时会怎样)📦
    • 本项目当前的选择与演示 🔭
    • 各可选方案与如何配置 🧰
      • 方案A:只用 BCrypt(工程上最常用)
      • 方案B:DelegatingPasswordEncoder(多算法兼容)
      • 方案C:PBKDF2(NIST 标准族)
      • 方案D:SCrypt(内存密集型,抗 ASIC)
    • 如何验证与体验(本项目)🕹️
    • 参数与性能建议 ⚖️
    • 密码升级(从旧算法迁移到新算法)🔄
    • 常见坑与规避 🧯
    • 在本项目怎么“换一种方式” 🛠️
    • 小结 ✅
    • 感谢

摘要

  • 讲清楚三件事:为什么必须加密、Spring Security/Boot 的默认行为、可选的加密算法与如何配置
  • 本项目已默认使用 BCrypt;提供演示页“密码加密对比”,控制台可直观看到每种算法的表现
  • 给出严谨的选型建议与“密码升级”方案,避免模糊/不实描述

为什么必须“加密”(准确说是单向散列)?🧠

  • 明文泄露=用户全线沦陷:大量用户跨站点复用密码
  • 撞库/字典/彩虹表:攻击者用常见口令或预计算表进行快速匹配
  • 不可逆+盐+慢:合格的口令存储必须具备
    • 不可逆(单向散列)
    • 随机盐(每个用户不同,抵御彩虹表)
    • 计算“有点慢”(加大攻击成本,可调“工作因子”)

对密码“加密”和“散列”的习惯混称在工程里常见,但用于口令存储的应是单向散列算法(BCrypt/PBKDF2/SCrypt/Argon2 等),而非可逆加密。


默认行为(不配置时会怎样)📦

  • Spring Security 推荐的“默认方案”是 DelegatingPasswordEncoder(多算法前缀格式),其默认 id 为 bcrypt。带前缀的存储形如:
    • {bcrypt}$2a101010……{pbkdf2}……{scrypt}……
  • Spring Boot 内置的属性用户(spring.security.user.password)如果你只写明文,Boot 会自动加 {noop} 前缀(仅用于快速演示,不推荐上线
  • DaoAuthenticationProvider 校验规则
    • 根据密文前缀 {id} 选用对应算法进行 matches(raw, encoded)
    • 没有前缀时,依赖你提供的 PasswordEncoder 决定如何处理

本项目在 config 模式下也会对 yml 中的密码进行编码保存,不以明文入库/入内存,因此不是 {noop}


本项目当前的选择与演示 🔭

  • 我们在 SecurityConfig 中声明了 BCryptPasswordEncoder,作为全局 PasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}
  • 三种认证来源(config/memory/database)最终都会走同一个 PasswordEncoder,因此:

    • 配置文件模式:启动时将 yml 的明文密码编码为 BCrypt
    • 内存模式:初始化用户时使用 BCrypt 编码
    • 数据库模式:入库即为 BCrypt 密文
  • 直观演示(控制台)

    • 启动自动打印“当前加密演示”,以及在页面“/password-demo”可一键对比:
      • BCrypt(推荐)
      • PBKDF2
      • SCrypt(已添加 BouncyCastle 依赖)
      • NoOp(仅测试)
      • DelegatingPasswordEncoder(多算法前缀)

image-20250813223004675


各可选方案与如何配置 🧰

方案A:只用 BCrypt(工程上最常用)

  • 特点:自带盐、每次结果不同、工作因子可调(cost)
  • 配置:保持当前 Bean 即可(推荐 cost 10–12,根据机器调整)

方案B:DelegatingPasswordEncoder(多算法兼容)

  • 适合渐进迁移(旧用户用旧算法,新用户用新算法)
  • 创建方式:PasswordEncoderFactories.createDelegatingPasswordEncoder()
  • 存储格式带 {id} 前缀,按前缀自动选择算法
String id = "bcrypt";
Map<String, PasswordEncoder> m = Map.of("bcrypt", new BCryptPasswordEncoder(),"pbkdf2", new Pbkdf2PasswordEncoder("", 8, 185000, Pbkdf2PasswordEncoder.SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA256),"scrypt", new SCryptPasswordEncoder(16384,8,1,32,64)
);
PasswordEncoder delegating = new DelegatingPasswordEncoder(id, m);

方案C:PBKDF2(NIST 标准族)

  • 可配置迭代次数,较通用
  • 本项目示例已使用 SHA-256 变体

方案D:SCrypt(内存密集型,抗 ASIC)

  • 更抗暴力破解,但依赖更复杂(我们已加入 BouncyCastle)
  • 依赖(已添加):
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk18on</artifactId><version>1.77</version>
</dependency>

注:Argon2 亦是优秀选择,但当前项目未演示,可在需要时加。


如何验证与体验(本项目)🕹️

  • 启动后访问:/password-demo
    • “当前项目密码加密方式”:看你现在的 PasswordEncoder 行为
    • “对比所有加密方式”:一次性打印 BCrypt/PBKDF2/SCrypt/NoOp/Delegating 的加密与校验结果
    • “密码强度”“加密性能”:帮助理解“慢即是安全”的含义
  • 控制台可见典型输出(两次加密不同 → 有盐;matches 为 true → 校验通过)

参数与性能建议 ⚖️

  • BCrypt cost(工作因子)建议 10–12(生产按 CPU 调整,以 100ms 级别为参考)
  • PBKDF2 迭代次数 150k–300k(随硬件演进调高)
  • SCrypt 参数(N=16384,r=8,p=1)为常见基线,按内存与性能压测校准
  • 目标是让“合法认证体验可接受、暴力破解代价高昂”

密码升级(从旧算法迁移到新算法)🔄

  • 场景:历史上存过明文/MD5/低 cost 的 BCrypt,希望“用户无感升级”
  • Spring Security 支持:UserDetailsPasswordService
    • 认证成功后,若 PasswordEncoder.upgradeEncoding(encoded) 返回 true,则回调 updatePassword 写回新密文
  • 推荐实践:在 database 模式下实现一个最小的 UserDetailsPasswordService,把新编码落库(与当前 UserRepository 配合即可)

常见坑与规避 🧯

  • 二次加密:重复 encode 导致永远匹配失败。规范:持久化前 encode;校验用 matches(raw, encoded)
  • 明文入库:严禁。演示专用 NoOp 切勿上线
  • 角色与权限映射:hasRole(“ADMIN”) → 实际校验 “ROLE_ADMIN”(本项目已正确映射)
  • 同一盐/固定盐:不可取。应依赖算法自身随机盐(如 BCrypt)
  • 算法迁移:使用 Delegating 前缀存储 + UserDetailsPasswordService 平滑升级

在本项目怎么“换一种方式” 🛠️

  • 保持“仅 BCrypt”:什么都不改(当前即如此)
  • 切换到 Delegating(多算法并行/迁移):
    1. 将 PasswordEncoder Bean 改为 DelegatingPasswordEncoder
    2. 旧密文前缀化或在数据库中逐步替换
    3. 可选:实现 UserDetailsPasswordService,登录即升级

小结 ✅

  • 必须用单向散列存储密码:不可逆+随机盐+可调慢
  • Spring Security 的推荐默认是 DelegatingPasswordEncoder(默认 bcrypt)
  • 本项目已采用 BCrypt 并提供对比演示页,便于你直观理解不同算法的行为
  • 若要面向未来做升级与兼容,优先考虑 Delegating + UserDetailsPasswordService

感谢

感谢你读到这里,说明你已经成功地忍受了我的文字考验!🎉
希望这篇文章没有让你想砸电脑,也没有让你打瞌睡。
如果有一点点收获,那我就心满意足了。

未来的路还长,愿你
遇见难题不慌张,遇见bug不抓狂,遇见好内容常回访
记得给自己多一点耐心,多一点幽默感,毕竟生活已经够严肃了。

如果你有想法、吐槽或者想一起讨论的,欢迎留言,咱们一起玩转技术,笑对人生!😄

祝你代码无bug,生活多彩,心情常青!🚀
在这里插入图片描述

http://www.dtcms.com/a/340140.html

相关文章:

  • 电子电气架构 --- 软件项目风险管理
  • ONVIF 设备debug: 设置onvif视频流配置的办法
  • 趣谈设计模式之策略模式-比特咖啡给你一杯满满的情绪价值,让您在数字世界里”畅饮“
  • 数据结构 -- 链表--单向链表的特点、操作函数
  • 【Git 子模块与动态路由映射技术分析文档】
  • 视觉测试:确保应用界面一致性
  • 数据结构 -- 单向链表的特点、操作函数
  • 使用segment-anything将目标检测label转换为语义分割label
  • 数据结构:二叉树oj练习
  • 实现进度条
  • 【大模型早期融合的非标记化架构】
  • 学习strandsagents的http_request tool
  • 【上升跟庄买入】副图/选股指标,动态黄色线由下向上穿越绿色基准线时,发出买入信号
  • Ubuntu 20 各种网卡配置IP的方法
  • 【PyTorch】多对象分割项目
  • 别再手动处理字符串!Python 正则表达式实战手册(入门到精通)
  • 【深度学习新浪潮】Meta 开源最新视觉大模型 DINOv3,该模型有哪些技术亮点?
  • 【数据结构】使用队列解决二叉树问题
  • CentOS安装SNMPWalk
  • C++高频知识点(二十二)
  • 算法题Day3
  • 理解MCP:开发者的新利器
  • 从零开始理解一个复杂的 C++/CUDA 项目 Makefile
  • React学习(六)
  • 梅森公式计算传递函数及结构图转换为信号流图过程
  • STM32-FreeRTOS快速入门指南(中)
  • HJ3 明明的随机数
  • 数据结构——双链表
  • 人工智能细分方向全景图:从入门到专精的技术路径
  • AI出题人给出的Java后端面经(十⑨)(日更)