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

密码加密算法和JWT无状态认证

加密算法分类

一、单向散列算法(不可逆,推荐用于密码存储)

单向散列算法通过哈希函数将任意长度的密码转换为固定长度的哈希值(密文),且无法从哈希值反推原始密码,是密码存储的首选方案。为增强安全性,通常会结合盐值(Salt) 使用(给每个密码添加随机字符串后再哈希,防止彩虹表攻击)。

1. MD5(Message-Digest Algorithm 5)
  • 特点:生成 128 位(16 字节)哈希值,运算速度快,但安全性极低。
  • 缺陷:已被证明存在严重漏洞,可通过碰撞攻击伪造相同哈希值的不同明文,不适合密码存储。
  • 现状:仅用于非安全场景(如文件校验),严禁用于密码加密。
2. SHA 系列(Secure Hash Algorithm)
  • SHA-1:生成 160 位哈希值,安全性低于 SHA-2,已被破解,不推荐用于密码。
  • SHA-2:包括 SHA-256、SHA-384、SHA-512 等,生成 256/384/512 位哈希值,安全性高,应用广泛。
    • 例:SHA-256 是目前主流选择,抗碰撞能力强,适合结合盐值存储密码。
  • SHA-3:SHA-2 的替代方案,基于全新算法设计,安全性更高,但目前应用较少。
3. BCrypt
  • 特点:专为密码哈希设计,基于 Blowfish 加密算法,自带盐值机制,且可通过 “工作因子” 调整运算复杂度(随硬件升级提高破解难度)。
  • 优势:不可逆、抗暴力破解能力强,是业界推荐的密码加密算法之一(如 Spring Security 默认支持)。

二、可逆加密算法(不推荐直接用于密码存储)

可逆加密算法(对称 / 非对称)可通过密钥解密得到原始密码,若密钥泄露,密码会直接暴露,因此不适合直接存储密码,仅用于临时加密传输场景。

1. 对称加密算法
  • AES(Advanced Encryption Standard):目前最流行的对称加密算法,支持 128/192/256 位密钥,安全性高、速度快。
  • DES/3DES:DES 已被破解,3DES 是 DES 的改进版但效率低,逐渐被 AES 替代。
2. 非对称加密算法
  • RSA:基于大数分解难题,用于密钥交换或数字签名,加密速度慢,不适合大量数据(如密码)加密。

三、密码加密的最佳实践

  1. 优先使用专用哈希算法:选择 BCrypt、Argon2 或 PBKDF2,避免 MD5、SHA-1。
  2. 强制使用盐值:每个密码对应唯一随机盐值,与哈希值一起存储(盐值无需保密)。
  3. 动态调整复杂度:根据硬件性能提高算法的迭代次数或内存消耗(如 BCrypt 的工作因子、Argon2 的内存参数)。
  4. 禁止可逆加密:除非特殊场景(如临时密码传输),否则不使用 AES、RSA 等可逆算法存储密码。

总结:Argon2 和 BCrypt 是当前密码加密的最优选择,兼顾安全性和实用性;SHA-256 结合盐值和高迭代次数可作为次选;MD5、DES 等已彻底淘汰。

BCrypt加密原理

代码实现:

##加密部分
public String encodePassword(String rawPassword) {if (rawPassword == null || rawPassword.isEmpty()) {throw new IllegalArgumentException("密码不能为空");}String encodedPassword = passwordEncoder.encode(rawPassword);log.debug("密码已加密");return encodedPassword;
}
##匹配部分
public boolean matches(String rawPassword, String encodedPassword) {if (rawPassword == null || encodedPassword == null) {return false;}boolean matches = passwordEncoder.matches(rawPassword, encodedPassword);log.debug("密码匹配结果: {}", matches);return matches;
}

1. 核心原理:加密算法的 “验证逻辑”

现代密码加密算法(如 BCrypt、Argon2、PBKDF2 等)的 matches 方法并非简单的 “重新加密原始密码并比较密文”,而是基于算法特性设计的验证逻辑:

  • 加密时,算法会自动生成随机盐值(salt),并将盐值与加密后的哈希值一起存储在 encodedPassword 中(密文通常包含盐值 + 哈希值 + 算法参数,格式如 $2a$10$N9qo8uLOickgx2ZMRZo5MeVQ82iT1M3Q)。
  • 验证时,matches 方法会:
    1. 从 encodedPassword 中解析出盐值、算法参数(如迭代次数、工作因子等)。
    2. 使用相同的盐值和参数,对用户输入的 rawPassword 执行相同的加密流程,生成临时哈希值。
    3. 比较临时哈希值与 encodedPassword 中存储的哈希值是否一致,一致则返回 true

2. 示例流程(以 BCrypt 为例)

假设你的 passwordEncoder 是 BCrypt 加密器:

  • 加密时
    passwordEncoder.encode("123456") 会生成类似 $2a$10$N9qo8uLOickgx2ZMRZo5MeVQ82iT1M3Q 的密文,其中:

    • $2a$ 表示 BCrypt 算法版本。
    • 10$ 表示工作因子(迭代次数)。
    • N9qo8uLOickgx2ZMRZo5Me 是随机盐值。
    • 后续部分是盐值 + 原始密码的哈希结果。
  • 验证时
    passwordEncoder.matches("123456", "$2a$10$N9qo8uLOickgx2ZMRZo5MeVQ82iT1M3Q") 会:

    1. 从密文中解析出盐值 N9qo8uLOickgx2ZMRZo5Me 和工作因子 10
    2. 用同样的盐值和工作因子,对输入的 123456 重新执行 BCrypt 加密。
    3. 比较新生成的哈希值与密文中的哈希部分是否相同,相同则返回 true

3. 为什么不需要手动处理盐值?

现代加密框架(如 Spring Security 的 PasswordEncoder)已封装了盐值的生成、存储和提取逻辑:

  • 盐值无需单独存储,而是嵌入在 encodedPassword 中。
  • matches 方法内部会自动解析盐值并复用加密参数,开发者无需关心细节。

总结

passwordEncoder.matches() 的核心是 “用密文中的盐值和参数重新加密原始密码,再对比哈希结果”,这保证了即使相同原始密码生成的密文不同(因盐值随机),仍能正确验证。这种机制既避免了盐值管理的复杂性,又保证了密码验证的安全性。

 

JWT无状态认证token 包含用户信息和过期时间

"token": "eyJhbGciOiJIUzUxMiJ9.eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoic2hhb3plbWluZyIsInN1YiI6InNoYW96ZW1pbmciLCJpYXQiOjE3NTU2ODA3MDYsImV4cCI6MTc1NTY4MTYwNn0.e_2SZzCHe_9uFXYicpyfyf-AM2WCuhp3x5IRZVsEwjsuQyx1mJ_KI_DkNqKqgu6UxDgdULiwCArVVOP2G6XddQ",

 解码分析

(1)Header(头部)

解码字符串:eyJhbGciOiJIUzUxMiJ9
Base64 解码后为 JSON:

{"alg": "HS512"
}
  • 含义:声明该 JWT 使用 HS512 算法进行签名(与你之前代码中使用的算法一致)。
(2)Payload(载荷)

解码字符串:eyJ1c2VySWQiOjEsInVzZXJuYW1lIjoic2hhb3plbWluZyIsInN1YiI6InNoYW96ZW1pbmciLCJpYXQiOjE3NTU2ODA3MDYsImV4cCI6MTc1NTY4MTYwNn0
Base64 解码后为 JSON:

{"userId": 1,"username": "shaozeming","sub": "shaozeming","iat": 1755680706,"exp": 1755681606
}

(3)Signature(签名)

最后一部分是签名:e_2SZzCHe_9uFXYicpyfyf-AM2WCuhp3x5IRZVsEwjsuQyx1mJ_KI_DkNqKqgu6UxDgdULiwCArVVOP2G6XddQ

  • 作用:由头部指定的 HS512 算法,结合服务器端的密钥对 Header 和 Payload 进行签名生成,用于验证令牌的完整性和真实性(防止被篡改)。

  • 无法解码,仅能通过服务器端的密钥验证有效性。

http://www.xdnf.cn/news/18408.html

相关文章:

  • [系统架构设计师]面向服务架构设计理论与实践(十五)
  • C++ 数据结构 和 STL
  • [Polly智能维护网络] 弹性上下文 | `ResiliencePropertyKey<TValue>`
  • WPF Alert弹框控件 - 完全使用指南
  • 2025年电赛A题省一方案
  • AR 虚实叠加技术在工业设备运维中的实现流程方案
  • 5G-A赋能AR眼镜:毫米级虚实融合的未来已来
  • 通过try-catch判断数据库唯一键字段是否重复
  • 网络流量分析——基础知识
  • MySQL 数据与表结构导出 Excel 技术文档
  • Ubuntu 主机名:精通配置与管理
  • Kafka-Eagle安装
  • SpringBoot + MyBatis-Plus 使用 listObjs 报 ClassCastException 的原因与解决办法
  • 自动驾驶汽车机器学习安全实用解决方案
  • Meta 再次重组人工智能部门
  • 自学嵌入式第二十三天:数据结构(3)-双链表
  • C语言基础:(二十)自定义类型:结构体
  • Linux 文本处理三剑客:awk、grep、sed 完全指南
  • 如何在 Ubuntu 24.04 配置 SFTP Server ?
  • AI 驱动三维逆向:点云降噪算法工具与机器学习建模能力的前沿应用
  • vue3源码reactivity响应式之数组代理的方法
  • MySQL/Kafka数据集成同步,增量同步及全量同步
  • 深入理解数据结构:从数组、链表到B树家族
  • 医疗AI与医院数据仓库的智能化升级:异构采集、精准评估与高效交互的融合方向(上)
  • 【工具使用-Docker容器】构建自己的镜像和容器
  • 栈上创建和堆上创建区别
  • 低开高走的典例:DeepSeek V3.1于8月19日晚更新:128K 上下文击败 Claude 4 Opus
  • 攻克PostgreSQL专家认证
  • RabbitMQ:消息转化器
  • Java EE ----- Spring Boot 日志