Golang中密码哈希与比较的实现方法

Golang中密码哈希与比较的实现方法 我尝试比较数据库密码和表单值密码时遇到以下错误: crypto/bcrypt: hashedPassword 不是给定密码的哈希值。我已附上相关代码函数

https://play.golang.org/p/Olq4APRNBDe

6 回复

非常感谢,它起作用了

更多关于Golang中密码哈希与比较的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


继续使用bcrypt,SHA1非常不安全。Bcrypt默认还会对密码进行加盐处理。

感谢George的回复,我使用了Yamil的代码并且成功了。

这段代码运行正常

package main

import (
	"fmt"
	"golang.org/x/crypto/bcrypt"
)

func main() {
	var err error

	passwordRequest := "Testx"
	passwordDB := "Test"

	bsp, err := bcrypt.GenerateFromPassword([]byte(passwordDB), bcrypt.DefaultCost)
	if err != nil {
		panic(err)
	}
	err = bcrypt.CompareHashAndPassword(bsp, []byte(passwordRequest))
	if err != nil {
		panic(err)
	} else {
		fmt.Println("password are equal")
	}
}

您也可以尝试直接从 SQL 命令进行身份验证,例如:

func sqlAuthenticateUser(u *User) error {
	if err := db.QueryRow("SELECT * FROM user WHERE email=? AND password=SHA1(?)", u.Email, u.Password).Scan(&u.Id, &u.Name, &u.Email, &u.Password, &u.isActive); err != nil {
		log.Println(err)
		return err
	}
	return nil
}

当然,在此之前您必须类似地插入加密密码。

在Go语言中,使用bcrypt包进行密码哈希和比较时,常见的错误是直接比较哈希后的字节数组或字符串,而不是使用bcrypt.CompareHashAndPassword函数。根据你提供的代码,问题可能出现在密码比较的方式上。以下是正确的实现方法:

密码哈希生成

首先,使用bcrypt.GenerateFromPassword生成密码的哈希值。这个函数会自动处理盐值,并返回哈希后的字节数组。

package main

import (
    "golang.org/x/crypto/bcrypt"
    "fmt"
)

func HashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
        return "", err
    }
    return string(bytes), nil
}

密码比较

使用bcrypt.CompareHashAndPassword函数来比较哈希密码和明文密码。这个函数会验证密码是否匹配,并返回错误(如果密码不匹配,则返回bcrypt.ErrMismatchedHashAndPassword)。

func CheckPasswordHash(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

完整示例

以下是一个完整的示例,展示如何生成密码哈希并在登录时进行比较:

package main

import (
    "golang.org/x/crypto/bcrypt"
    "fmt"
)

func main() {
    password := "secretpassword"
    
    // 生成哈希密码
    hash, err := HashPassword(password)
    if err != nil {
        fmt.Println("Error hashing password:", err)
        return
    }
    fmt.Println("Hashed Password:", hash)
    
    // 模拟从数据库获取的哈希密码
    storedHash := hash
    
    // 检查密码是否匹配
    match := CheckPasswordHash(password, storedHash)
    if match {
        fmt.Println("Password matches!")
    } else {
        fmt.Println("Password does not match!")
    }
    
    // 测试错误密码
    wrongPassword := "wrongpassword"
    match = CheckPasswordHash(wrongPassword, storedHash)
    if match {
        fmt.Println("Wrong password matched (unexpected)!")
    } else {
        fmt.Println("Wrong password correctly rejected.")
    }
}

func HashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    if err != nil {
        return "", err
    }
    return string(bytes), nil
}

func CheckPasswordHash(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

关键点说明

  • 不要直接比较哈希字符串bcrypt生成的哈希包含盐值和成本参数,直接字符串比较会失败。
  • 使用CompareHashAndPassword:这个函数内部处理了哈希解析和比较逻辑。
  • 错误处理:如果密码不匹配,CompareHashAndPassword会返回一个错误,你可以检查err == bcrypt.ErrMismatchedHashAndPassword来具体处理不匹配的情况。

在你的代码中,确保在比较时使用bcrypt.CompareHashAndPassword而不是直接比较字符串或字节数组。如果问题仍然存在,检查从数据库获取的哈希值是否正确存储和检索,没有额外的空格或编码问题。

回到顶部