[英]Why does Spring's MessageDigestPasswordEncoder take `{}` into the salt? The example in its javadoc does not seem to work
I'm upgrading from Spring Security 4.x to 5.x. 我正在从Spring Security 4.x升级到5.x。
The ReflectionSaltSource
from Spring 4 lets us configure a custom salt. Spring 4的
ReflectionSaltSource
使我们可以配置自定义盐。 But that's removed in Spring Security 5. I then found out that I should use MessageDigestPasswordEncoder
. 但这在Spring Security 5中已删除。然后我发现我应该使用
MessageDigestPasswordEncoder
。 It has a long detailed java-doc but unfortunately the doc is a bag of words without conveying any structured information (I tried multiple times; my bad if I was ignorant). 它有一个很长的详细的Java文档,但是不幸的是,该文档是一堆单词,没有传达任何结构化的信息(我尝试了多次;如果我一无所知,那会很糟糕)。
Anyways I thought I should do the following based on my limited understanding. 无论如何,基于我的有限理解,我认为我应该执行以下操作。
Old system with 4.x - myEncodedPassword
and mySalt
are passed separately to the encoder. 使用4.x的旧系统
myEncodedPassword
和mySalt
分别传递到编码器。
New System with 5.x - Pass one field with the value {mySalt}myEncodedPassword
to the MessageDigestPasswordEncoder
使用5.x的新系统 -将值为
{mySalt}myEncodedPassword
一个字段{mySalt}myEncodedPassword
给MessageDigestPasswordEncoder
However, that did not work. 但是,那没有用。 The Problem was that when
MessageDigestPasswordEncoder
sees {mySalt}encodedPassword
, it uses {mySalt}
(with the {}) as the salt instead of using mySalt
as the salt . 问题在于,当
MessageDigestPasswordEncoder
看到{mySalt}encodedPassword
,它使用{mySalt}
(带有{})作为盐,而不是使用mySalt
作为盐。 I'm confused. 我糊涂了。
Here's a coding example. 这是一个编码示例。 I used Groovy to reduce noise.
我使用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?
The output is 输出是
expected=true, actual=false
expected=false, actual=true
I'm hoping to find a way to support SHA256 with custom and separate salt for each user password. 我希望找到一种方法为每个用户密码使用自定义和单独的盐支持SHA256。
If anyone's interested, I created a ticket on GitHub - https://github.com/spring-projects/spring-security/issues/6594 . 如果有人感兴趣,我会在GitHub- https://github.com/spring-projects/spring-security/issues/6594上创建票证。 No solution so far.
到目前为止没有解决方案。 I will update here if there's any.
如果有的话,我会在这里更新。 So this is still an unanswered question.
因此,这仍然是一个悬而未决的问题。
I guess the issue is in the org.springframework.security.crypto.password.MessageDigestPasswordEncoder
class 我猜问题出在
org.springframework.security.crypto.password.MessageDigestPasswordEncoder
类中
By debugging it in the method private String extractSalt(String prefixEncodedPassword)
they try to extract salt by returning prefixEncodedPassword.substring(start, end + 1);
通过在
private String extractSalt(String prefixEncodedPassword)
方法中对其进行调试,他们尝试通过返回prefixEncodedPassword.substring(start, end + 1);
来提取盐prefixEncodedPassword.substring(start, end + 1);
where start
is the index of the prefix {
while end is the index of suffix }
and it stops to the first suffix it matches so what happens in your code? 其中
start
是前缀{
的索引,而end是后缀的索引}
,并且停止到它匹配的第一个后缀,那么代码中会发生什么?
It happens this: 发生这种情况:
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
I state I don't know if it's a bug or not, in any case in your scenario it should be enough to properly investigate and properly modify the method 我声明我不知道它是否是错误,无论如何在您的情况下,它都足以正确调查和正确修改方法
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);
}
This method is inside the org.springframework.security.crypto.password.MessageDigestPasswordEncoder
class 此方法在
org.springframework.security.crypto.password.MessageDigestPasswordEncoder
类内部
I hope it's useful 我希望它有用
Angelo 安杰洛
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.