Bcrypt加密每次使用相同的输入都不同

问题描述 投票:1回答:2

使用golang.org/x/crypto/bcrypt和GORM(http://gorm.io/docs/)我正在尝试加密密码。问题是它的每次加密都是不同的,所以它永远不会匹配数据库中的那个。

var result []string

password := []byte(data.Password)
encryptedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) // different every time

db.Where(&User{Username: strings.ToLower(data.Username)}).First(&user).Pluck("password", &result)
encryptionErr := bcrypt.CompareHashAndPassword(encryptedPassword, []byte(result[0]))

if encryptionErr == nil { // passwords match! }

我已经确认每次输入都是相同的,并且数据库提供的密码是正确的。

我在这做错了什么?

go
2个回答
1
投票

根据设计,bcrypt hash algorithm每次调用它时都会生成一个不同的加密字符串(它是salted)。如果您有要检查的明文密码和数据库中的密文,您应该能够将这两件事传递给bcrypt.CompareHashAndPassword。调整代码:

var result []string
db.Where(&User{Username: strings.ToLower(data.Username)})
        .First(&user)
        .Pluck("password", &result)

encryptionErr := bcrypt.CompareHashAndPassword([]byte(result[0]), []byte(data.Password))

你不应该再打电话给bcrypt.GenerateFromPassword;正如您所注意到的,它将生成一个不同的加密密码,并且应该几乎无法比较两者的相等性。


4
投票

问题是它的每次加密都是不同的,所以它永远不会匹配数据库中的那个。

这是正常的bcrypt行为。

bcrypt每次都返回一个不同的哈希,因为它在哈希中包含了一个不同的随机值。这被称为“盐”。它可以防止人们使用“彩虹表”攻击您的散列密码,预先生成的表映射密码会回显到他们的密码。 salt表示没有密码的一个哈希值,而是有2 ^ 16个。存储太多了。

salt存储为哈希密码的一部分。所以bcrypt.CompareHashAndPassword(encryptedPassword, plainPassword)可以使用与plainPassword相同的盐加密encryptedPassword并进行比较。

请参阅this answer for more information和Dustin Boswell的优秀Storing User Passwords Securely: hashing, salting, and Bcrypt

我在这做错了什么?

您正在尝试将生成的散列密码与存储的散列密码进行比较。至少我当然希望它是存储在数据库中的哈希密码。

您想要的是将存储的散列密码与用户输入的普通密码进行比较。

// Normally this comes from user input and is *never* stored
plainPassword := "supersekret"

// The encrypted password is stored in the database
db.Where(&User{Username: strings.ToLower(data.Username)}).First(&user).Pluck("password", &result)
encryptedPassword := []byte(result[0])

// Check if the stored encrypted password matches "supersekret"
encryptionErr := bcrypt.CompareHashAndPassword(encryptedPassword, plainPassword)
if encryptionErr == nil {
    fmt.Println("Greetings Professor Falken")
} else {
    fmt.Println(encryptionErr)
}
© www.soinside.com 2019 - 2024. All rights reserved.