上一期的文章《咱们应该如何保护用户的密码》里咱们介绍了bcrypt
相较于MD5
,SHA-1
...SHA-256
等哈希算法更适合用于作密码的哈希,缘由就是bcrypt
算法哈希字符串的速度远远慢于上面列举的那些算法。这样即便整个用户密码库被用户盗用后想要经过彩虹表和暴力破解的方法猜想出用户的密码代价会很是高昂。今天的文章里就主要来看一下bcrypt
哈希的组成部分以及在Go
语言里如何使用bcrypt
对密码字符串进行哈希。golang
bcrypt
哈希由多个部分组成。这些部分用于肯定建立哈希的设置,从而能够在不须要任何其余信息的状况下对其进行验证。算法
上图是一个bcrypt
哈希的示例图,其由四部分组成:shell
Prefix
说明了使用的bcrypt
的版本Cost
是进行哈希的次数-数字越大生成bcrypt
的速度越慢,成本越大。一样也意味着若是密码库被盗,攻击者想经过暴力破解的方法猜想出用户密码的成本变得越昂贵。Salt
是添加到要进行哈希的字符串中的随机字符(21.25个字符),因此使用bcrypt
时不须要咱们在表里单独存储Salt
。Hashed Text
是明文字符串最终被bcrypt
应用这些设置哈希后的哈希文本。另外不管什么方法:每一个密码加单独的盐进行哈希,使用bcrypt
进行哈希等等,若是用户使用很是简单的密码例如password
或123456
,仍是能被猜想出来的,因此在用户设置密码时应该禁止他们输入简单的密码。编程
bcrypt
的原理和实现都很是复杂,不过经常使用的编程语言都有实现bcrypt
的包让咱们直接使用,在Go
语言里是经过golang.org/x/crypto/bcrypt
包提供bcrypt
相关功能给开发者使用的。服务器
接下来咱们在http_demo
项目里演示一下使用bcrypt
作密码哈希和验证的方法,首先咱们须要安装一下bcrypt
包编程语言
$ go get golang.org/x/crypto/bcrypt
bcrypt
包只提供了三个函数:函数
CompareHashAndPassword
用于比对bcrypt
哈希字符串和提供的密码明文文本是否匹配。GenerateFromPassword
以给定的Cost
返回密码的bcrypt
哈希。若是给定的成本小于MinCost
,则将成本设置为DefaultCost
(10)。Cost
返回用于建立给定bcrypt
哈希的哈希成本。未来密码系统为了应对更大的计算能力而增长哈希成本时,该功能能够用于肯定哪些密码须要更新。咱们建立一个处理请求的Handler
程序,演示bcrypt
库三个函数的功能spa
// ./handler/password_hashing.go package handler import ( "fmt" "golang.org/x/crypto/bcrypt" "net/http" ) func HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) return string(bytes), err } func CheckPasswordHash(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } func GetHashingCost(hashedPassword []byte) int { cost, _ := bcrypt.Cost(hashedPassword) // 为了简单忽略错误处理 return cost } func PassWordHashingHandler(w http.ResponseWriter, r *http.Request) { password := "secret" hash, _ := HashPassword(password) // 为了简单忽略错误处理 fmt.Fprintln(w,"Password:", password) fmt.Fprintln(w, "Hash: ", hash) match := CheckPasswordHash(password, hash) fmt.Fprintln(w,"Match: ", match) cost := GetHashingCost([]byte(hash)) fmt.Fprintln(w,"Cost: ", cost) }
增长Handler
程序的路由:code
func RegisterRoutes(r *mux.Router) { ... indexRouter := r.PathPrefix("/index").Subrouter() indexRouter.HandleFunc("/password_hashing", handler.PassWordHashingHandler) ... }
重启http_demo
服务器后访问http://localhost:8000/index/password_hashing
便可获得以下结果:router
Password: secret Hash: $2a$14$Ael8nW7UF/En/iI7LGdyBuaIO8VREbL2CAShRN0EUQHqtmOHXh.XK Match: true Cost: 14
本文源代码已经打包上传,公众号回复gohttp13
便可得到下载连接。若是以为个人文章有收获,请帮忙点"在看"分享给更多人。