Go Libs :bcrypt (安全密码加密)

前言

在系统开发中,为了保护用户的密码安全,不被恶意窃取,我们需要对密码进行加密和验证。本文将介绍Go语言如何使用bcrypt库来实现安全的密码加密。

首先,为什么要加密?试想,如果服务器的数据库被盗,那攻击者就可以拿着明文的密码进行登入篡改、信息泄露等。

一些基础

  • bcrypt: 是专门为密码存储而设计的算法,基于Blowfish加密算法变形而来,由Niels Provos和David Mazières发表于1999年的USENIX。
  • SALT值(盐值): 属于随机值.用户注册时,系统用来和用户密码进行组合而生成的随机数值,称作salt值,通称为加盐值。
  • 彩虹表: 预先计算出所有可能的hash值,比如6位密码的所有hash值(大小写加数字,只有62^6个)

加密过程与原理

当用户首次提供密码时(通常是注册时),由系统自动添加随机生成的salt值,然后再散列。而当用户登录时,系统为用户提供的代码撒上同样的加盐值,然后散列,再比较散列值,以确定密码是否正确。

为用户密码添加Salt值,使得加密的得到的密文更加冷僻,不宜查询。即使黑客有密文查询到的值,也是加了salt值的密码,而非用户设置的密码。salt值是随机生成的一组字符串,可以包括随机的大小写字母、数字、字符,位数可以根据要求而不一样。

bcrypt

bcrypt 包实现了 Provos 和 Mazières 的 bcrypt 自适应哈希算法。

加密过程与源码

  1. 生成盐值:在对密码进行哈希之前,需要生成一个随机的盐值。 源码参考:
go 复制代码
unencodedSalt := make([]byte, maxSaltSize)
_, err = io.ReadFull(rand.Reader, unencodedSalt)
if err != nil {
    return nil, err
} 
  1. 使用生成的盐值和密码进行哈希运算。源码参考:
go 复制代码
p.salt = base64Encode(unencodedSalt)
hash, err := bcrypt(password, p.cost, p.salt)
if err != nil {
    return nil, err
}
  1. 可选修改迭代次数来增加哈希函数的计算复杂度, 增加迭代次数会导致哈希函数的计算时间增加,从而增加攻击者破解密码的难度。源码参考:
go 复制代码
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
 csalt, err := base64Decode(salt)
 if err != nil {
    return nil, err
 }

 // Bug compatibility with C bcrypt implementations. They use the trailing
 // NULL in the key string during expansion.
 // We copy the key to prevent changing the underlying array.
 ckey := append(key[:len(key):len(key)], 0)

 c, err := blowfish.NewSaltedCipher(ckey, csalt)
 if err != nil {
    return nil, err
 }

 var i, rounds uint64
 rounds = 1 << cost
 for i = 0; i < rounds; i++ {
    blowfish.ExpandKey(ckey, c)
    blowfish.ExpandKey(csalt, c)
 }

 return c, nil
}

使用Bcrypt进行密码加密的一个例子:

first 安装

arduino 复制代码
go get golang.org/x/crypto/bcrypt

Example:

go 复制代码
package main

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

func main() {
    var (
       password = "123456"
    )

    hashedPassword, err := HashPassword(password)
    if err != nil {
       fmt.Println("Error hashing password:", err)
       return
    }

    fmt.Println("未加密:", password)
    fmt.Println("加密后:", hashedPassword)

    if err := CheckPasswordHash("202020", hashedPassword); err != nil {
       fmt.Println("密码不匹配:", err)
    } else {
       fmt.Println("密码匹配")
    }

    if err := CheckPasswordHash(password, hashedPassword); err != nil {
       fmt.Println("密码不匹配:", err)
    } else {
       fmt.Println("密码匹配!")
    }
}

func CheckPasswordHash(password, hash string) error {
    return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
}

func HashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10)
    return string(bytes), err
} 

执行输出:

js 复制代码
未加密: 123456
加密后: $2a$10$EvmU.zY9qGx7QntUFG9Qf.G6SRytkf8GMtFMsn1IYjnIMbZ6gUd4O
密码不匹配: crypto/bcrypt: hashedPassword is not the hash of the given password
密码匹配!

注意:

  • bcrypt接受最长密码的长度 72 字节,在使用时注意密码长度
  • 迭代次数 Cost 如果给定的成本小于 MinCost(4),则成本将改为 DefaultCos(10)

小结

为了保护用户的密码不被恶意攻击者窃取,如服务器数据库被盗、 碰撞、彩虹表等,可以通过使用Bcrypt算法加密。同时介绍了加密的过程和Go Bcrypt源码,包括生成随机盐值、安全哈希值和修改迭代次数。文中通过一个示例,演示了如何使用进行加密、校验的过程。

参考

相关推荐
章豪Mrrey nical3 小时前
前后端分离工作详解Detailed Explanation of Frontend-Backend Separation Work
后端·前端框架·状态模式
派大鑫wink4 小时前
【JAVA学习日志】SpringBoot 参数配置:从基础到实战,解锁灵活配置新姿势
java·spring boot·后端
程序员爱钓鱼4 小时前
Node.js 编程实战:文件读写操作
前端·后端·node.js
xUxIAOrUIII4 小时前
【Spring Boot】控制器Controller方法
java·spring boot·后端
Dolphin_Home4 小时前
从理论到实战:图结构在仓库关联业务中的落地(小白→中级,附完整代码)
java·spring boot·后端·spring cloud·database·广度优先·图搜索算法
zfj3214 小时前
go为什么设计成源码依赖,而不是二进制依赖
开发语言·后端·golang
weixin_462446235 小时前
使用 Go 实现 SSE 流式推送 + 打字机效果(模拟 Coze Chat)
开发语言·后端·golang
JIngJaneIL5 小时前
基于springboot + vue古城景区管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
小信啊啊5 小时前
Go语言切片slice
开发语言·后端·golang
Victor3567 小时前
Netty(20)如何实现基于Netty的WebSocket服务器?
后端