密码加密
图常见方案 Hash 算法
最早我们使用类似 SHA-256、SHA-512、 MD5等这样的单向 Hash 算法。用户注册成功 后,保存在数据库中不再是用户的明文密码,而是经过 SHA-256 加密计算的一个字行串, 当用户进行登录时,用户输入的明文密码用 SHA-256 进行加密,加密完成之后,再和存储 在数据库中的密码进行比对,进而确定用户登录信息是否有效。如果系统遭遇攻击,最多也 只是存储在数据库中的密文被泄漏。 这样就绝对安全了吗?由于彩虹表这种攻击方式的存在以及随着计算机硬件的发展,每秒 执行数十亿次 HASH计算己经变得轻轻松松,这意味着即使给密码加密加盐也不我安全。 参考:彩虹表
单向自适应函数
在Spring Security 中,我们现在是用一种自适应单向函数 (Adaptive One-way Functions)来处 理密码问题,这种自适应单向西数在进行密码匹配时,会有意占用大量系统资源(例如 CPU、内存等),这样可以增加恶意用户攻击系统的难度。在Spring Securiy 中,开发者可 以通过 bcrypt、PBKDF2、 sCrypt 以及 argon2 来体验这种自适应单向函数加密。由于自适应 单向西数有意占用大量系统资源,因此每个登录认证请求都会 是 Spring Secuity不会采取任何措施来提高密码验证速度,因为 OCR工具 能,但 增强 系统的安全性。
BCryptPasswordEncoder:使用 bcrypt 算法对密码进行加密,为了提高密码的安全性, bcrypt算法故意降低运行速度,以增强密码破解的难度。同时 BCryptP asswordEncoder “为自己带盐”开发者不需要额外维护一个“盐”字段,使用 BCryptPasswordEncoder 加密 后的字符串就已经“带盐”了,即使相同的明文每次生成的加密字符串都不相同。
Argon2PasswordEncoder:使用 Argon2 算法对密码进行加密,Argon2曾在 Password Hashing Competition 竞赛中获胜。为了解决在定制硬件上密码容易被破解的问题, Argon2也是故意降低运算速度,同时需要大量内存,以确保系统的安全性。
Pbkdf2PasswordEncoder:使用 PBKDF2 算法对密码进行加密,和前面几种类似,PBKDF2 算法也是一种故意降低运算速度的算法,当需要 FIPS (Federal Information Processing Standard,美国联邦信息处理标准)认证时,PBKDF2 算法是一个很好的选择。
SCryptPasswordEncoder 使用scrypt 算法对密码进行加密,和前面的几种类似, serypt 也 是一种故意降低运算速度的算法,而且需要大量内存。
PassowrdEncoder
通过对认证流程源码分析得知,实际密码比较是由PasswordEncoder完成的,因此只需要使用PasswordEncoder不同实现就可以实现不同方式的加密。
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matche(CharSequence rawPassword, String encodedPassword);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
encode
:用来对明文加密进行加密。matches
:用来比较密码的方法。upgradeEncoding
:用来给密码升级的方法。
根据上面 PasswordEncoder的介绍,可能会以为 Spring security 中默认的密码加密方案应该 是四种自适应单向加密函数中的一种,其实不然,在 spring Security 5.0之后,默认的密码 加密方案其实是 DelegatingPasswordEncoder。从名字上来看,DelegatingPaswordEncoder是 一个代理类,而并非一种全新的密码加密方案,DeleggtinePasswordEncoder 主要用来代理 上面介绍的不同的密码加密方案。的什么采DelegatingPasswordEncoder 而不是某一个具体 加密方式作为默认的密码加密方案呢?主要考虑了如下两方面的因素:
兼容性:使用 DelegatingPasswrordEncoder 可以帮助许多使用旧密码加密方式的系统顺 利迁移到 Spring security 中,它允许在同一个系统中同时存在多种不同的密码加密方 案。
便捷性:密码存储的最佳方案不可能一直不变,如果使用 DelegatingPasswordEncoder作 为默认的密码加密方案,当需要修改加密方案时,只需要修改很小一部分代码就可以实 现。
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
密码自动升级
推荐使用DelegatingPasswordEncoder
的另外一个好处就是自动进行密码加密方案的升级, 这个功能在整合一些老的系统时非常有用。
@Service
public class MyUserDetailesService implements UserDetailsService, UserDetailsPasswordService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
// 更新密码的加密方式
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
// 根据用户名更新密码
// Integer updatePasswordByUsername(String username, String password);
// 如果更新成功,返回更新后的用户信息
// user.setPassword(newPassword);
return null;
}
}
最后更新于
这有帮助吗?