微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring Security:如果版本和强度值发生变化,BCryptPasswordEncoder 可以正常工作

如何解决Spring Security:如果版本和强度值发生变化,BCryptPasswordEncoder 可以正常工作

使用 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).

是的,但我们在比较时不会生成新的盐,我们在从数据库中获取的密码上使用盐。

如果我们查找关于 bcryptwikipedia,我们会看到以下关于 $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
}

他们只会检查您提供的版本是否有效。之后,他们从存储在数据库中的密码中提取盐,然后用该盐对密码进行哈希处理,然后进行比较。

构造函数设置将仅应用于新散列的密码。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。