Golang的md5

MD5 简介

MD5(Message-Digest Algorithm 5)是一种常用的散列函数,用于生成唯一的固定长度的哈希值。散列函数可用于验证数据的完整性,因为任何对数据的更改都会导致哈希值的变化。

使用 MD5

在 Go 语言中,您可以使用 md5 包计算 MD5 哈希值。首先,您需要创建一个 md5.New 的实例,该实例实现了哈希.Hash 接口。然后,您可以使用 Write 方法将数据写入哈希。最后,您可以使用 Sum 方法计算哈希值。

package main

import (
"crypto/md5"
"fmt"
"io"
)

func main() {
h := md5.New()
io.WriteString(h, "Hello, world!")
fmt.Printf("%x\n", h.Sum(nil)) // Output: 6cd3556deb0da54bca060b4c39479839
}

注意事项

请注意,MD5 哈希算法已被认为不安全,不应在新的系统中使用。在大多数情况下,应使用更安全的哈希算法,例如 SHA-2 或 SHA-3。另外,在使用 MD5 哈希算法时,还应该注意避免使用明文密码,因为 MD5 哈希算法是不可逆的。因此,建议在存储用户密码时使用盐(salt),以防止彩虹表攻击。

使用场景

  • 校验文件完整性:在文件传输过程中,可以使用 MD5 计算文件的哈希值,并在接收后再次计算哈希值进行比对,以确保文件在传输过程中没有损坏。
  • 密码存储:在用户注册时,可以使用 MD5 哈希函数存储用户的密码

数据库的应用实例

在数据库中使用 MD5 哈希算法主要用于存储加密后的密码。这样即使数据库被泄露,攻击者也无法直接获取用户的密码。

下面是一个使用 MySQL 数据库的示例:

CREATE TABLE users (
username VARCHAR(255) NOT NULL,
password CHAR(32) NOT NULL,
PRIMARY KEY (username)
);
// 在插入新用户时,可以使用 MySQL 的 MD5 函数计算密码的哈希值:
INSERT INTO users (username, password) VALUES ('user1', MD5('password'));

// 在验证用户登录时,可以使用相同的函数计算用户输入的密码的哈希值并与数据库中存储的哈希值进行比对:
SELECT * FROM users WHERE username='user1' AND password=MD5('password');

扩展

  • 盐(salt)
    盐(salt)是一个随机字符串,用于加强散列函数的安全性。在存储用户密码时,可以将盐添加到密码中,然后使用散列函数计算哈希值。这样,即使两个用户使用相同的密码,它们也会产生不同的哈希值,因为它们使用的盐不同。
    例如,假设用户 A 和用户 B 都使用密码 "password",并且使用盐 "salty" 和 "pepper"。在使用散列函数计算哈希值时,它们的密码分别为 "passwordsalty" 和 "passwordpepper"。这样,即使攻击者知道了用户 A 和用户 B 的哈希值,也无法确定它们使用的密码。
    为了防止彩虹表攻击,盐应当具有足够的随机性,且应存储在数据库中的密码哈希值之外。这样,即使攻击者获得了数据库中的哈希值,也无法使用彩虹表进行暴力破解

  • 彩虹表攻击
    彩虹表是一种用于暴力破解散列函数的技术。它使用一张预先计算出的表格,该表格中包含了大量常用密码的哈希值。在攻击过程中,攻击者会使用彩虹表尝试匹配被攻击的数据库中的哈希值,如果匹配成功,则说明找到了对应的密码。
    举个例子,假设有一个名为 "users" 的数据库,其中包含了用户名和哈希后的密码。攻击者希望破解这个数据库,于是使用彩虹表攻击。首先,攻击者会使用彩虹表中的哈希值尝试匹配 "users" 数据库中的哈希值。如果匹配成功,则可以找到对应的密码,并使用该密码登录。
    为了防止彩虹表攻击,建议使用盐(salt)来加强散列函数的安全性。盐是一个随机字符串,可以在存储密码时与密码一起使用散列函数计算哈希值。这样,即使两个用户使用相同的密码,它们也会产生不同的哈希值,因为它们使用的盐不同。

  • golang加盐
    在 Go 语言中,您可以使用 crypto/rand 包生成随机盐。例如,您可以使用 crypto/rand.Read 函数生成随机字节数组,然后将其转换为字符串即可。

package main
import (
"crypto/rand"
"fmt"
"io"
)

func generateSalt() string {
b := make([]byte, 16)
_, err := io.ReadFull(rand.Reader, b)
if err != nil {
return ""
}
return fmt.Sprintf("%x", b)
}

func main() {
fmt.Println(generateSalt()) // Output: 8ec1c9b9a4b2e3f3d4c5a6b7c8d9e0f1
}

然后,您可以将盐与密码一起使用散列函数计算哈希值。
例如,使用 MD5 哈希算法:

package main

import (
"crypto/md5"
"fmt"
"io"
)

func hashPassword(password, salt string) string {
h := md5.New()
io.WriteString(h, password+salt)
return fmt.Sprintf("%x", h.Sum(nil))
}

func main() {
password := "password"
salt := "salty"
fmt.Println(hashPassword(password, salt)) // Output: b3b3c55a087b3fddb9f9aabcfd1f5bac
}

在存储密码时,需要将盐和哈希值一起存储到数据库中。在验证用户登录时,可以先获取用户输入的密码、盐和哈希值,然后使用相同的散列函数计算哈希,然后与数据库中存储的哈希值进行比对。如果匹配成功,则说明用户输入的密码正确,可以允许用户登录。

posted @ 2023-01-06 10:38  黄建威  阅读(5219)  评论(0)    收藏  举报