七、密码加密
简介
- 加密意义
2011年12月21日,有人在网络上公开了一个包含600万个 优快云 用户资资料的数据库,数据全部为明文储存,包含用户名、密码以及注册邮箱。事件发生后优快云在微博、官方网站等渠道发出了声明,解释说此数据库系2009年备份所用,因不明原因泄漏 已经向警方报案,后又在官网发出了公开道歉信。在接下来的十多天里,金山、网易 京东、当当、新浪等多家公司被卷入到这次事件中。整个事件中最触目惊心的莫过于 优快云 把用户密码明文存储,由于很多用户是多个网站共用一个密码,因此一个网站密码泄漏就会造成很大的安全隐患。 由于有了这么多前车之鉴,我们现在做系统时,密码都要加密处理
在前面的案例中,凡是涉及密码的地方,我们都采用明文存储,在实际项目中这肯定是不可取的,因为这会带来极高的安全风险。在企业级应用中,密码不仅需要加密,还需要加盐,最大程度地保证密码安全。
-
常见方案
- Hash 算法
最早我们使用类似 SHA-256、SHA-512、MD5 等这样的单向 Hash 算法。用户注册成功后,保存在数据库中不再是用户的明文密码,而是经过 SHA-256 加密计算的一个字行串,当用户进行登录时,用户输入的明文密码用 SHA-256 进行加密,加密完成之后,再和存储在数据库中的密码进行比对,进而确定用户登录信息是否有效。如果系统遭遇攻击,最多也只是存储在数据库中的密文被泄漏
这样就绝对安全了吗?由于彩虹表这种攻击方式的存在以及随着计算机硬件的发展,每秒执行数十亿次 HASH 计算己经变得轻轻松松,这意味着即使给密码加密加盐也不再安全
- 单向自适应函数
在Spring Security中,我们现在是用一种自适应单向函数(AdaptiveOne-wayFunctions)来处理密码问题,这种自适应单向函数在进行密码匹配时,会有意占用大量系统资源(例如 CPU、内存等),这样可以增加恶意用户攻击系统的难度,在 Spring Securiy 中,开发者可以通过 bcrypt、PBKDF2、sCrypt 以及 argon2 来体验这种自适应单向函数加密。由于自适应单向函数有意占用大量系统资源,因此每个登录认证请求都会大大降低应用程序的性能,但是 Spring Secuity 不会采取任何措施来提高密码验证速度,因为它正是通过这种方式来增强系统的安全性
-
密码介绍
参考1:https://byronhe.gitbooks.io/libsodium/content/password_hashing
- BCryptPasswordEncoder
BCryptPasswordEncoder 使用 bcrypt 算法对密码进行加密,为了提高密码的安全性,bcrypt 算法故意降低运行速度,以增强密码破解的难度。同时 BCryptPasswordEncoder “为自己带盐” 开发者不需要额外维护一个 “盐” 字段,使用 BCryptPasswordEncoder 加密后的字符串就已经 “带盐” 了,即使相同的明文每次生成的加密字符串都不相同
- Argon2PasswordEncoder
Argon2PasswordEncoder 使用 Argon2 算法对密码进行加密,Argon2 曾在 Password Hashing Competition竞赛中获胜。为了解决在定制硬件上密码容易被破解的问题, Argon2 也是故意降低运算速度,同时需要大量内存,以确保系统的安全性
- Pbkdf2PasswordEncoder
Pbkdf2PasswordEncoder 使用 PBKDF2 算法对密码进行加密,和前面几种类似,PBKDF2 算法也是一种故意降低运算速度的算法,当需要 FIPS(Federal Information Processing Standard,美国联邦信息处理标准)认证时,PBKDF2算法是一个很好的选择
- SCryptPasswordEncoder
SCryptPasswordEncoder 使用 scrypt 算法对密码进行加密,和前面的几种类似,scrypt 也是一种故意降低运算速度的算法,而且需要大量内存
7.1 检验密码源码分析
PasswrodEncoder 与 DelegatingPasswordEncoder 关系
- 首先,我们来进行一下认证的源码分析,根据前面介绍,对于用户的认证是由 ProviderManager 去进行校验的

- 再认证的过程中,对于密码的匹配调用了 DaoAuthenticationProvider 类中的 additionalAuthenticationChecks() 方法。(注:这里并不是 AbstractUserDetailsAuthenticationProvider 中的 additionalAuthenticationChecks() 方法,而是 DaoAuthenticationProvider 继承了 AbstractUserDetailsAuthenticationProvider)如下图所示


可以看到这里的调用了this.passwordEncoder.matches(presentedPassword, userDetails.getPassword()),这个this.passwordEncoder 是 PasswordEncoder 接口

接口 PasswordEncoder 有诸多实现类,都是不同类型的密码匹配规则

继续debug,发现这个PasswordEncoder 实现类叫做 DelegatingPasswordEncoded

进入这个 DelegatingPasswordEncoded 代理类实现的matches()方法,发现这个代理 PasswordEncoder 根据密文的前缀{noop}来获取真正用来加密的实现类(典型的策略设计模式)




PasswrodEncoder 接口

本文详细介绍了密码加密的重要性,以及常见的加密方案,如Hash算法、彩虹表攻击和自适应单向函数。重点讲解了SpringSecurity中使用BCrypt、Argon2、PBKDF2和scrypt等算法的PasswordEncoder接口,特别是DelegatingPasswordEncoder的使用,它允许系统同时支持多种加密方式,并具备密码自动升级功能。此外,还展示了如何在实际项目中配置和使用这些加密方式,确保用户密码的安全。
最低0.47元/天 解锁文章
1104

被折叠的 条评论
为什么被折叠?



