每次使用相同的输入进行Bcrypt加密都会有所不同

时间:2018-08-31 18:43:50

标签: go

我使用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! }

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

我在这里做什么错了?

2 个答案:

答案 0 :(得分:4)

  

问题在于每种加密方式每次都不相同,因此它永远无法与数据库中的加密方式匹配。

这是正常的bcrypt行为。

bcrypt每次都会返回不同的哈希值,因为它会将不同的随机值合并到哈希值中。这就是所谓的“盐”。它可以防止人们使用“彩虹表”来攻击您的哈希密码,该彩虹表是一个预先生成的将密码哈希映射回其密码的表。盐表示,密码不是2个哈希值,而是1个哈希值。存储太多。

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

请参见this answer for more information和达斯汀·波斯威尔的出色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)
}

答案 1 :(得分: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;正如您所注意到的,它将生成一个不同的加密密码,几乎不可能将两者进行相等性比较。