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源码,包括生成随机盐值、安全哈希值和修改迭代次数。文中通过一个示例,演示了如何使用进行加密、校验的过程。

参考

相关推荐
程序员爱钓鱼6 小时前
Go语言实战案例 — 工具开发篇:实现一个图片批量压缩工具
后端·google·go
ChinaRainbowSea8 小时前
7. LangChain4j + 记忆缓存详细说明
java·数据库·redis·后端·缓存·langchain·ai编程
舒一笑8 小时前
同步框架与底层消费机制解决方案梳理
后端·程序员
minh_coo8 小时前
Spring框架事件驱动架构核心注解之@EventListener
java·后端·spring·架构·intellij-idea
白初&9 小时前
SpringBoot后端基础案例
java·spring boot·后端
计算机学姐11 小时前
基于Python的旅游数据分析可视化系统【2026最新】
vue.js·后端·python·数据分析·django·flask·旅游
该用户已不存在12 小时前
你没有听说过的7个Windows开发必备工具
前端·windows·后端
David爱编程12 小时前
深入 Java synchronized 底层:字节码解析与 MonitorEnter 原理全揭秘
java·后端
KimLiu12 小时前
LCODER之Python:使用Django搭建服务端
后端·python·django
再学一点就睡13 小时前
双 Token 认证机制:从原理到实践的完整实现
前端·javascript·后端