跳到主要内容

Go 盐值加密和密码生成

· 阅读需 4 分钟
素明诚
Full stack development

盐值加密是一种安全策略,用于增强存储在数据库中的密码的安全性。在这个过程中,每个密码都会随机添加一个数据片段,即“盐”,这样即使两个用户使用相同的密码,它们存储在数据库中的形式也会不同。这种方法可以有效地抵抗彩虹表攻击等密码攻击技术。我尽可能的用最简短的话讲明白这个流程。

流程详解

首次设定密码时的操作

  • 用户设置密码。
  • 系统生成一个随机的盐值。
  • 系统将这个盐值和用户的密码合并后,通过哈希函数生成哈希值。
  • 将生成的盐值和哈希值一起存储在数据库中(通常是同一字段,例如在 bcrypt 中,盐和哈希值是一起编码在一个字符串中)。

用户登录时的操作

  • 用户输入密码。
  • 系统从数据库中取出含盐的哈希值。
  • 系统从存储的哈希值中解析出盐值(对于 bcrypt 等库,这一步是自动完成的)。
  • 系统使用提取出的盐值和用户输入的密码重新进行哈希操作。
  • 系统比较这个新生成的哈希值和数据库中存储的哈希值,如果相同,则验证成功;如果不同,则密码错误。

关键点

  • 盐的重用:验证密码时使用的盐是第一次生成并存储的盐,不是每次都重新生成的。这保证了只要输入的密码正确,无论验证多少次,生成的哈希值总是一致的。
  • 存储方式:在像 bcrypt 这样的现代密码哈希库中,盐值是自动与哈希值一起生成和存储的。你不需要手动处理盐的存储和提取,库会为你管理这些细节。

Go 语言实现盐值加密的示例

以下是一个使用 Go 语言和golang.org/x/crypto/bcrypt库来实现盐值哈希的示例。这个库自动处理盐的生成和存储。

package main

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

// GenerateHash 使用bcrypt生成盐值哈希
func GenerateHash(password string) (string, error) {
// GenerateFromPassword 自动添加盐并生成哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hashedPassword), nil
}

// ComparePasswords 比较用户输入的密码和数据库中的哈希
func ComparePasswords(hashedPwd string, plainPwd string) bool {
// CompareHashAndPassword 比较哈希和密码
err := bcrypt.CompareHashAndPassword([]byte(hashedPwd), []byte(plainPwd))
return err == nil
}

func main() {
// 用户设置的密码
password := "securepassword123"

// 生成哈希
hashedPassword, err := GenerateHash(password)
if err != nil {
fmt.Println("Error hashing password:", err)
return
}
fmt.Println("Hashed Password:", hashedPassword)

// 验证密码
match := ComparePasswords(hashedPassword, "securepassword123")
fmt.Println("Password match:", match)
}

使用bcrypt.GenerateFromPassword生成一个盐值哈希。这个函数自动为每个密码生成一个随机盐,并将盐和哈希存储在同一个字符串中。当需要验证密码时,使用bcrypt.CompareHashAndPassword可以自动处理盐的提取和比对过程。这使得实现更加简单且安全。

需要注意的点

合适的哈希算法

  • 安全性:选择已经经过广泛验证且被认为是安全的哈希函数,如bcryptscryptArgon2,而不是快速的哈希函数如 MD5 或 SHA-1,因为它们容易受到快速暴力攻击。
  • 更新性:随着计算能力的提升,一些原本认为安全的算法可能变得不再安全,因此需要持续关注和更新所使用的算法。

盐的唯一性和随机性

  • 随机性:盐应该是完全随机生成的,以确保每个哈希都是唯一的,即使是对于相同的密码。
  • 唯一性:为每个密码实例使用不同的盐,即使是同一个用户的密码更新,也应重新生成新的盐。

存储安全

  • 分离存储:虽然盐值需要和哈希值一起存储,但应确保这些信息的存储方式足够安全,例如使用加密的数据库或安全的存储解决方案。
  • 访问控制:确保只有必要的应用程序和人员能访问存储密码的数据库。

性能考虑

  • 处理时间bcrypt和类似的算法设计时就考虑到了耗时较长,以阻碍暴力破解攻击。但这也意味着在实际应用中可能需要考虑到算法对性能的影响。
  • 负载调整:可以通过调整算法的工作因子来平衡安全性和性能需求,如bcryptcost参数。