java - 为什么 Spring 的 MessageDigestPasswordEncoder 将 `{}` 放入盐中? javadoc 中的示例似乎不起作用

标签 java spring spring-security

我正在从 Spring Security 4.x 升级到 5.x。

Spring 4 中的 ReflectionSaltSource 允许我们配置自定义盐。但这在 Spring Security 5 中被删除了。然后我发现我应该使用 MessageDigestPasswordEncoder。它有一个很长、详细的 java 文档,但不幸的是,该文档是一堆文字,没有传达任何结构化信息(我尝试了多次;如果我无知,那我就不好了)。

无论如何,我认为基于我有限的理解,我应该做以下事情。

4.x 的旧系统 - myEncodedPasswordmySalt 分别传递到编码器。

5.x 的新系统 - 将一个值为 {mySalt}myEncodedPassword 的字段传递给 MessageDigestPasswordEncoder

但是,这并没有奏效。 问题是,当 MessageDigestPasswordEncoder 看到 {mySalt}encodedPassword 时,它会使用 {mySalt}(带有 {} ) 作为盐,而不是使用 mySalt 作为盐。我很困惑。

这是一个编码示例。我使用 Groovy 来减少噪音。

@Grab(group='org.springframework.security', module='spring-security-core', version='5.1.4.RELEASE')
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder

String password = 'myPassword'
String salt_1 = 'mySalt'
String salt_2 = '{mySalt}'
// http://www.lorem-ipsum.co.uk/hasher.php generated below hashes
String encodedPasswordWithSalt_1 = '57bc828628811a10496215e217b7ae9b714c859fc7a8b1c678c9a0cc40aac422'
String encodedPasswordWithSalt_2 = 'a18b53fc58843def1e08e00a718f40d6f8eda0b97ef97824b5078c1fad93c0c5'

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder('SHA-256')
println "expected=true, actual=" + encoder.matches(password, "{${salt_1}}${encodedPasswordWithSalt_1}") // <--- expected to match but did not
println "expected=false, actual=" + encoder.matches(password, "{${salt_1}}${encodedPasswordWithSalt_2}") // <--- why does this match?

输出为

expected=true, actual=false
expected=false, actual=true

我希望找到一种方法来支持 SHA256,为每个用户密码提供自定义和单独的盐。

<小时/>

如果有人感兴趣,我在 GitHub 上创建了一张票 - https://github.com/spring-projects/spring-security/issues/6594 。目前还没有解决办法。如果有的话我会在这里更新。所以这仍然是一个悬而未决的问题。

最佳答案

我猜问题出在 org.springframework.security.crypto.password.MessageDigestPasswordEncoder

通过在方法 private String extractSalt(String prefixEncodedPassword) 中进行调试,他们尝试通过返回 prefixEncodedPassword.substring(start, end + 1); 来提取盐,其中 start 是前缀 { 的索引,而 end 是后缀 } 的索引,它停止到它匹配的第一个后缀,所以你的代码中会发生什么代码?

事情发生是这样的:

MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder('SHA-256')
println "expected=true, actual=" + encoder.matches(password, "{${salt_1}}${encodedPasswordWithSalt_1}") //It's not matched because the extracted salt will be {mySalt} and not mySalt
println "expected=false, actual=" + encoder.matches(password, "{${salt_1}}${encodedPasswordWithSalt_2}") //It's matched because the extracted salt will be {mySalt} and not mySalt

我声明我不知道这是否是一个错误,无论如何,在您的情况下,正确调查并正确修改该方法应该足以

private String extractSalt(String prefixEncodedPassword) {
        int start = prefixEncodedPassword.indexOf(PREFIX);
        if (start != 0) {
            return "";
        }
        int end = prefixEncodedPassword.indexOf(SUFFIX, start);
        if (end < 0) {
            return "";
        }
        return prefixEncodedPassword.substring(start, end + 1);
    }

此方法位于org.springframework.security.crypto.password.MessageDigestPasswordEncoder类内部

希望有用

安杰洛

关于java - 为什么 Spring 的 MessageDigestPasswordEncoder 将 `{}` 放入盐中? javadoc 中的示例似乎不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55031118/

相关文章:

使用 Android AudioRecord 时出现 java.lang.NullPointerException

java - izpack 自定义信息国际化

java - 绑定(bind) XML POJO 类数据类型 - 应用程序设计

spring - 如何使用log4j2在记录文件中记录Spring JdbcTemplate SQL查询和数据库响应

java - 延迟加载处理(Hibernate + Spring MVC)

java - EntityManager.remove 和 EntityManager.persist 上的 JPA 重复条目错误

spring - 使用IP地址和用户名密码的Spring安全认证

java - 删除的对象将通过级联重新保存

java - 使用不带 LoadTimeWeaving 的服务自定义 UserDetails

java - 如何在 Spring Security 中使用自定义角色/权限?