问题描述
使用 Spring Boot CLI 可以执行以下操作:
spring encodepassword secret
该命令打印的位置
{bcrypt}$2a$10$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbiqrq6afgzk6
因此密码 secret
被编码为 {bcrypt}$2a$10$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbiqrq6afgzk6
,观察 $2a$10 和 {bcrypt} 部分
已声明:
@Bean
PasswordEncoder encoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
强制使用以下内容:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("some_user")
.password("{bcrypt}$2a$10$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbiqrq6afgzk6")
.authorities("ROLE_SOME_ROLE");
Observe 是强制使用 {bcrypt}
,更多细节在 PasswordEncoderFactories 类(对于 createDelegatingPasswordEncoder
方法),因为 DelegatingPasswordEncoder 类是在幕后使用的。>
如果我不使用
@Bean
PasswordEncoder encoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
并且仅替换为:
@Bean
PasswordEncoder bcryptEncoder() {
return new BCryptPasswordEncoder(BCryptVersion.$2A,10);// or new BCryptPasswordEncoder()
}
观察:来自上面
-
BCryptPasswordEncoder(BCryptVersion.$2A,10)
或new BCryptPasswordEncoder()
几乎相同,请参阅 BCryptPasswordEncoder 类的更多详细信息 - 观察
$2A,10
部分,它与$2a$10
匹配(来自密码)。
现在是强制使用:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("some_user")
.password("$2a$10$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbiqrq6afgzk6")
.authorities("ROLE_SOME_ROLE");
Observe 是强制性的不使用{bcrypt}
,因为DelegatingPasswordEncoder 类在幕后不再使用。否则无法登录。
直到这里都有意义
现在的困惑如下:
如果使用:
@Bean
PasswordEncoder bcryptEncoder() {
return new BCryptPasswordEncoder(BCryptVersion.$2Y,12);
}
观察:现在使用了 $2Y,12
,它与 $2A,10
(因此与 $2a$10
密码部分/部分)完全不同。
情况
还可以进行登录过程。我认为这一定是不可能的,因为模式不一样。顺便说一句,我确实在项目中做了 clean compile
。
发生了什么?
解决方法
Observation: now $2Y,12 is used and it is totally different than $2A,10 (and therefore than the $2a$10 password part/section).
是的,但我们在比较时不会生成新的盐,我们在从数据库中获取的密码上使用盐。
如果我们查找关于 bcrypt
的 wikipedia,我们会看到以下关于 $2Y
2011 年 6 月,在 BCrypt 的 PHP 实现 crypt_blowfish 中发现了一个错误。这是错误处理第 8 位设置的字符。他们建议系统管理员更新他们现有的密码数据库,用 $2x$ 替换 $2a$,以表明这些哈希是错误的(并且需要使用旧的损坏算法)。他们还提出了让 crypt_blowfish 为固定算法生成的散列发出 $2y$ 的想法。
没有其他人,包括规范的 OpenBSD,采用 2x/2y 的想法。此版本标记更改仅限于 crypt_blowfish。
作为没有此漏洞的 spring 实现,$2Y$
与 $2A$
本质上相同。
当我们查看 BCrypt#checkpw
的源代码时,我们看到以下内容:
/**
* Check that a password (as a byte array) matches a previously hashed one
* @param passwordb the password to verify,as a byte array
* @param hashed the previously-hashed password
* @return true if the passwords match,false otherwise
* @since 5.3
*/
public static boolean checkpw(byte[] passwordb,String hashed) {
return equalsNoEarlyReturn(hashed,hashpw(passwordb,hashed));
}
将获取的密码作为第二个参数传入 this function。
public static String hashpw(byte passwordb[],String salt) {
// omitted code
// Here we extract the salt from the provided hashed password
real_salt = salt.substring(off + 3,off + 25);
// omitted code
}
他们只会检查您提供的版本是否有效。之后,他们从存储在数据库中的密码中提取盐,然后用该盐对密码进行哈希处理,然后进行比较。
构造函数设置将仅应用于新散列的密码。