Java 为什么 Spring 的 BCryptPasswordEncoder 为相同的输入生成不同的输出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25844419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 01:15:58  来源:igfitidea点击:

Why BCryptPasswordEncoder from Spring generate different outputs for same input?

javaspringspring-securitybcrypt

提问by Bhavesh

I am using BCryptPasswordEncoderwith Spring security. My expectation was that for the same input I will always get the same output. But for the same input I get different output. You could test it with the code snippet below:

我正在使用具有 Spring 安全性的BCryptPasswordEncoder。我的期望是对于相同的输入,我将始终获得相同的输出。但是对于相同的输入,我得到不同的输出。您可以使用以下代码片段对其进行测试:

String password = "123456"; 
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 
String encodedPassword = passwordEncoder.encode(password);
System.out.print(encodedPassword);

output: $2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

output2: $2a$10$KEvYX9yjj0f1X3Wl8S.KPuWzSWGyGM9ubI71NOm3ZNbJcwWN6agvW

output3: $2a$10$nCmrPtUaOLn5EI73VZ4Ouu1TmkSWDUxxD4N6A.8hPBWg43Vl.RLDC

输出:$2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

输出 2:$2a$10$KEvYX9yjj0f1X3Wl8S.KPuWzSWGyGM9ubI71NOm3ZNbJcwWN6agvW

输出 3:$2a$10$nCmrPtUaOLn5EI73VZ4Ouu1TmkSWDUxxD4N6A.8hPBWg43Vl.RLDC

Could someone explain, why BCryptPasswordEncoder behave like this?

有人可以解释一下,为什么 BCryptPasswordEncoder 会这样?

采纳答案by blueberry0xff

public static void main(String[] args) {
  // spring 4.0.0
  org.springframework.security.crypto.password.PasswordEncoder encoder
   = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder();

   // a$lB6/PKg2/JC4XgdMDXyjs.dLC9jFNAuuNbFkL9udcXe/EBjxSyqxW
   // true
   // a$KbQiHKTa1WIsQFTQWQKCiujoTJJB7MCMSaSgG/imVkKRicMPwgN5i
   // true
   // aWfW4uxVb4SIdzcTJI9U7eU4ZwaocrvP.2CKkWJkBDKz1dmCh50J2
   // true
   // a##代码##wR/6uaPxU7kGyUIsx/JS.krbAA9429fwsuCyTlEFJG54HgdR10nK
   // true
   // a$gfmnyiTlf8MDmwG7oqKJG.W8rrag8jt6dNW.31ukgr0.quwGujUuO
   // true

    for (int i = 0; i < 5; i++) {
      // "123456" - plain text - user input from user interface
      String passwd = encoder.encode("123456");

      // passwd - password from database
      System.out.println(passwd); // print hash

      // true for all 5 iteration
      System.out.println(encoder.matches("123456", passwd));
    }
}

回答by geoand

That is perfectly normal because BCryptPasswordEncoderuses a salt to generate the password. You can read about the idea behind "salting" a password hereand here.

这是完全正常的,因为BCryptPasswordEncoder使用盐来生成密码。您可以在此处此处阅读有关“加盐”密码背后的想法。

This is what the documentation says for the encodemethod

这是文档中对该encode方法的说明

Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or greater hash combined with an 8-byte or greater randomly generated salt.

对原始密码进行编码。通常,好的编码算法应用 SHA-1 或更大的哈希值与 8 字节或更大的随机生成的盐值相结合。

回答by Uwe Plonus

The generated password are salted and therefore different.

生成的密码是加盐的,因此不同。

Please read the documentation for the encode()method where it clearly states the the password is salted.

请阅读encode()方法的文档,其中明确说明密码已加盐。

回答by user1364368

The 22 characters directly after the 2nd $ represent the salt value, see https://en.wikipedia.org/wiki/Bcrypt#Description. "Salt" is some random data added to the password before hashing, so a given hash algorithm with given parameters will in most cases produce different hash values for the same password (protection against so called rainbow attacks).

紧跟在第二个 $ 之后的 22 个字符表示盐值,请参阅https://en.wikipedia.org/wiki/Bcrypt#Description。“盐”是在散列之前添加到密码中的一些随机数据,因此具有给定参数的给定散列算法在大多数情况下会为同一密码生成不同的散列值(防止所谓的彩虹攻击)。

Let's dissect the first output shown in the original question: $2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

让我们剖析原始问题中显示的第一个输出: $2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

  • $2a: Identifier for BCrypt algorithm
  • $10: Parameter for number of rounds, here 2^10 rounds
  • cYLM.qoXpeAzcZhJ3oXRLu: Salt (128 bits)
  • 9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi: Actual hash value (184 bits)
  • $2a: BCrypt 算法的标识符
  • $10: 轮数参数,这里是 2^10 轮
  • cYLM.qoXpeAzcZhJ3oXRLu:盐(128 位)
  • 9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi: 实际哈希值(184 位)

The salt and the hash value are both encoded using Radix-64.

盐和哈希值都使用 Radix-64 编码。