我正在从 Spring Security 4.x 升级到 5.x。
Spring 4 中的 ReflectionSaltSource
允许我们配置自定义盐。但这在 Spring Security 5 中被删除了。然后我发现我应该使用 MessageDigestPasswordEncoder
。它有一个很长、详细的 java 文档,但不幸的是,该文档是一堆文字,没有传达任何结构化信息(我尝试了多次;如果我无知,那我就不好了)。
无论如何,我认为基于我有限的理解,我应该做以下事情。
4.x 的旧系统 - myEncodedPassword
和 mySalt
分别传递到编码器。
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/