Spring 安全性:无论版本和强度值是否更改,BCryptPasswordEncoder 都能正常工作
Spring Security: BCryptPasswordEncoder works without matter if the Version and Strength values are changed
使用 Spring 引导 CLI 可以执行以下操作:
spring encodepassword secret
该命令打印的位置
{bcrypt}a$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbIqRq6afgzk6
因此密码secret
被编码为{bcrypt}a$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}a$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbIqRq6afgzk6")
.authorities("ROLE_SOME_ROLE");
Observe 是强制使用 {bcrypt}
,PasswordEncoderFactories class (for the createDelegatingPasswordEncoder
method), it because the DelegatingPasswordEncoder 中有更多详细信息 class 在幕后使用。
如果我不使用
@Bean
PasswordEncoder encoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
并仅替换为:
@Bean
PasswordEncoder bcryptEncoder() {
return new BCryptPasswordEncoder(BCryptVersion.A, 10);// or new BCryptPasswordEncoder()
}
观察: 从上方
BCryptPasswordEncoder(BCryptVersion.A, 10)
或 new BCryptPasswordEncoder()
实际上是相同的,请参阅 BCryptPasswordEncoder class 更多详细信息
- 观察
A, 10
部分,它匹配 a
(来自密码)。
现在强制使用:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("some_user")
.password("a$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbIqRq6afgzk6")
.authorities("ROLE_SOME_ROLE");
Observe is mandatory not use {bcrypt}
, 因为DelegatingPasswordEncoder class is not 在幕后使用了。否则无法登录。
到这里都懂了
现在的困惑是:
如果使用:
@Bean
PasswordEncoder bcryptEncoder() {
return new BCryptPasswordEncoder(BCryptVersion.Y, 12);
}
观察:现在使用 Y, 12
,它与 A, 10
完全不同(因此与 a
密码 part/section).
情况
可以做登录过程呢。我认为那一定是不可能的,因为模式不一样。顺便说一句,我确实在项目中做了 clean compile
。
发生了什么事?
Observation: now Y, 12 is used and it is totally different than A, 10 (and therefore than the a password part/section).
是的,但是我们在比较时不生成新的盐,我们在从数据库中获取的密码上使用盐。
如果我们查找 wikipedia 关于 bcrypt
我们会看到以下关于 Y
In June 2011, a bug was discovered in crypt_blowfish, a PHP implementation of BCrypt. It was mis-handling characters with the 8th bit set. They suggested that system administrators update their existing password database, replacing a$ with x$, to indicate that those hashes are bad (and need to use the old broken algorithm). They also suggested the idea of having crypt_blowfish emit y$ for hashes generated by the fixed algorithm.
Nobody else, including canonical OpenBSD, adopted the idea of 2x/2y. This version marker change was limited to crypt_blowfish.
因为没有这个漏洞的spring实现Y$
与A$
基本相同。
当我们查看 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
}
他们只会检查您提供的版本是否有效。之后,他们从存储在数据库中的密码中提取盐,然后用该盐对密码进行哈希处理,然后进行比较。
构造函数设置将仅应用于新散列的密码。
使用 Spring 引导 CLI 可以执行以下操作:
spring encodepassword secret
该命令打印的位置
{bcrypt}a$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbIqRq6afgzk6
因此密码secret
被编码为{bcrypt}a$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}a$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbIqRq6afgzk6")
.authorities("ROLE_SOME_ROLE");
Observe 是强制使用 {bcrypt}
,PasswordEncoderFactories class (for the createDelegatingPasswordEncoder
method), it because the DelegatingPasswordEncoder 中有更多详细信息 class 在幕后使用。
如果我不使用
@Bean
PasswordEncoder encoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
并仅替换为:
@Bean
PasswordEncoder bcryptEncoder() {
return new BCryptPasswordEncoder(BCryptVersion.A, 10);// or new BCryptPasswordEncoder()
}
观察: 从上方
BCryptPasswordEncoder(BCryptVersion.A, 10)
或new BCryptPasswordEncoder()
实际上是相同的,请参阅 BCryptPasswordEncoder class 更多详细信息- 观察
A, 10
部分,它匹配a
(来自密码)。
现在强制使用:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("some_user")
.password("a$ZjFpLGhApSqM1ftCBOPvt.3aV3l5dsRawW61ZCX2lbIqRq6afgzk6")
.authorities("ROLE_SOME_ROLE");
Observe is mandatory not use {bcrypt}
, 因为DelegatingPasswordEncoder class is not 在幕后使用了。否则无法登录。
到这里都懂了
现在的困惑是:
如果使用:
@Bean
PasswordEncoder bcryptEncoder() {
return new BCryptPasswordEncoder(BCryptVersion.Y, 12);
}
观察:现在使用 Y, 12
,它与 A, 10
完全不同(因此与 a
密码 part/section).
情况
可以做登录过程呢。我认为那一定是不可能的,因为模式不一样。顺便说一句,我确实在项目中做了 clean compile
。
发生了什么事?
Observation: now Y, 12 is used and it is totally different than A, 10 (and therefore than the a password part/section).
是的,但是我们在比较时不生成新的盐,我们在从数据库中获取的密码上使用盐。
如果我们查找 wikipedia 关于 bcrypt
我们会看到以下关于 Y
In June 2011, a bug was discovered in crypt_blowfish, a PHP implementation of BCrypt. It was mis-handling characters with the 8th bit set. They suggested that system administrators update their existing password database, replacing a$ with x$, to indicate that those hashes are bad (and need to use the old broken algorithm). They also suggested the idea of having crypt_blowfish emit y$ for hashes generated by the fixed algorithm.
Nobody else, including canonical OpenBSD, adopted the idea of 2x/2y. This version marker change was limited to crypt_blowfish.
因为没有这个漏洞的spring实现Y$
与A$
基本相同。
当我们查看 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
}
他们只会检查您提供的版本是否有效。之后,他们从存储在数据库中的密码中提取盐,然后用该盐对密码进行哈希处理,然后进行比较。
构造函数设置将仅应用于新散列的密码。