【问题标题】:Spring Security: BCryptPasswordEncoder works without matter if the Version and Strength values are changedSpring Security:无论版本和强度值是否更改,BCryptPasswordEncoder 都可以正常工作
【发布时间】:2021-01-21 00:19:18
【问题描述】:

使用 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");

观察是强制使用{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");

观察是强制性的使用{bcrypt},这是因为DelegatingPasswordEncoder不再在幕后使用。否则无法登录。

直到这里都有意义

现在混乱如下:

如果使用:

@Bean
PasswordEncoder bcryptEncoder() {
    return new BCryptPasswordEncoder(BCryptVersion.$2Y, 12);
}

观察:现在使用$2Y, 12,它与$2A, 10 完全不同(因此也不同于$2a$10 密码部分/部分)。

情况 还可以进行登录过程。我认为这一定是不可能的,因为模式不一样。顺便说一句,我确实在项目中做了clean compile

那么发生了什么?

【问题讨论】:

    标签: java spring-security bcrypt


    【解决方案1】:

    Observation: now $2Y, 12 is used and it is totally different than $2A, 10 (and therefore than the $2a$10 password part/section).

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

    如果我们查找wikipedia 关于bcrypt,我们会看到以下关于$2Y 的信息

    2011 年 6 月,在 BCrypt 的 PHP 实现 crypt_blowfish 中发现了一个错误。这是第 8 位设置的错误处理字符。他们建议系统管理员更新他们现有的密码数据库,将 $2a$ 替换为 $2x$,以表明这些哈希是错误的(并且需要使用旧的损坏算法)。他们还提出了让 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
    }
    

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

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

    【讨论】:

    • 有趣,因为在BCryptPasswordEncoder类的底部有3个版本,2a,2y,2b
    • 顺便说一句:BCrypt.checkpw 对吗? github.com/spring-projects/spring-security/blob/…
    • borth 函数,你列出的函数,它所做的只是调用这个github.com/spring-projects/spring-security/blob/… 来获取字节然后调用下一个。为什么 spring 已经完成了你必须问他们的版本的设计选择。
    • 我写了第二条评论,因为我发现了一个错误并且已经修复了。不是BCryptPasswordEncoder#checkpw,必须是BCrypt#checkpw
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    • 2017-04-29
    • 1970-01-01
    • 2020-02-09
    • 2021-09-20
    • 2013-05-06
    • 2017-02-01
    相关资源
    最近更新 更多