Go使用SM3哈希算法和隨機(jī)鹽實(shí)現(xiàn)用戶密碼加密
前言
在現(xiàn)代 Web 系統(tǒng)中,用戶密碼安全存儲(chǔ)是非常關(guān)鍵的一環(huán)。
傳統(tǒng)做法用簡單哈希,容易受到彩虹表攻擊。
本文將介紹如何使用 SM3 哈希算法 + 隨機(jī)鹽 (salt) 來加密用戶密碼,并提供 Go 語言實(shí)現(xiàn)示例。
一、為什么要加鹽 (Salt)
直接哈希密碼存在以下問題:
彩虹表攻擊
- 攻擊者可以通過預(yù)先計(jì)算的哈希表快速破解常用密碼。
相同密碼哈希值相同
- 用戶 A 和用戶 B 使用相同密碼,會(huì)生成相同哈希值,增加泄露風(fēng)險(xiǎn)。
解決方案:
在密碼哈希前增加隨機(jī)鹽 (Salt),每個(gè)用戶的密碼哈希值都不同,即使密碼相同也不會(huì)重復(fù)。
二、SM3 哈希算法
SM3 是中國國家標(biāo)準(zhǔn)的哈希算法(國密算法),具有:
- 輸出長度 256 位
- 安全性高,適用于密碼存儲(chǔ)
- 廣泛應(yīng)用于金融和安全系統(tǒng)
在 Go 中可以使用 github.com/tjfoc/gmsm/sm3 來實(shí)現(xiàn) SM3 哈希。
三、Go 實(shí)現(xiàn)用戶密碼加密
下面是一套完整的 SM3 密碼加密方案:
1. 生成隨機(jī)鹽
func generateSalt() (string, error) {
b := make([]byte, 16) // 16字節(jié)隨機(jī)鹽
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
- 使用
crypto/rand生成安全隨機(jī)數(shù) - 轉(zhuǎn)為十六進(jìn)制字符串存儲(chǔ)
2. SM3 哈希函數(shù)
func sm3Hash(password, salt string) string {
h := sm3.New()
h.Write([]byte(password + salt))
return hex.EncodeToString(h.Sum(nil))
}
- 將密碼和鹽拼接后進(jìn)行 SM3 哈希
- 返回十六進(jìn)制字符串
3. 生成哈希密碼
func HashPassword(password string) (string, error) {
salt, err := generateSalt()
if err != nil {
return "", err
}
hash := sm3Hash(password, salt)
return fmt.Sprintf("sm3$v1$%s$%s", salt, hash), nil
}
- 存儲(chǔ)格式為:
sm3$v1$<salt_hex>$<hash_hex> - 包含算法標(biāo)識(shí)、版本、鹽和哈希值,便于版本升級(jí)和兼容不同算法
4. 驗(yàn)證密碼
func CheckPassword(dbPassword, inputPassword string) (bool, error) {
parts := strings.Split(dbPassword, "$")
if len(parts) != 4 {
return false, errors.New("hash 格式不正確")
}
_, version, salt, hash := parts[0], parts[1], parts[2], parts[3]
if version != "v1" {
return false, errors.New("不支持的版本")
}
calculatedHash := sm3Hash(inputPassword, salt)
return calculatedHash == hash, nil
}
- 從數(shù)據(jù)庫中取出存儲(chǔ)的哈希
- 提取鹽和版本信息
- 對(duì)輸入密碼進(jìn)行同樣哈希并對(duì)比
5. 可擴(kuò)展支持多種算法
代碼中還可以支持 bcrypt 或其他哈希算法:
func CheckPassword(dbPassword, inputPassword, hashAlgo string) (bool, error) {
switch hashAlgo {
case "bcrypt":
return bcrypt.CompareHashAndPassword([]byte(dbPassword), []byte(inputPassword)) == nil, nil
case "sm3":
return CheckPassword(dbPassword, inputPassword)
default:
return false, errors.New("未知 hash 算法")
}
}
- 方便未來系統(tǒng)遷移或混合使用多種哈希方案
四、完整示例
func main() {
password := "123456"
hash, _ := HashPassword(password)
fmt.Println("存儲(chǔ)密碼:", hash)
ok, _ := CheckPassword(hash, password)
fmt.Println("驗(yàn)證密碼:", ok)
}
輸出示例:
存儲(chǔ)密碼: sm3$v1$e2a3f4...$9f8d7c... 驗(yàn)證密碼: true
五、小結(jié)
- 使用 SM3 + 隨機(jī)鹽,可以安全存儲(chǔ)用戶密碼
- 存儲(chǔ)格式建議包含算法和版本號(hào),便于升級(jí)
- 密碼驗(yàn)證時(shí)只需從數(shù)據(jù)庫取出鹽和哈希值即可
- 結(jié)合 Go 的標(biāo)準(zhǔn)庫和
gmsm/sm3,可以快速落地
使用 SM3 哈希和鹽的方式,能有效抵御彩虹表攻擊和密碼重復(fù)泄露風(fēng)險(xiǎn),是企業(yè)級(jí)系統(tǒng)密碼安全存儲(chǔ)的可靠方案。
到此這篇關(guān)于Go使用SM3哈希算法和隨機(jī)鹽實(shí)現(xiàn)用戶密碼加密的文章就介紹到這了,更多相關(guān)Go SM3哈希和隨機(jī)鹽實(shí)現(xiàn)密碼加密內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Golang中for-loop與goroutine的問題詳解
這篇文章主要給大家介紹了關(guān)于Golang中for-loop與goroutine問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09
服務(wù)器端Go程序?qū)﹂L短鏈接的處理及運(yùn)行參數(shù)的保存
這篇文章主要介紹了服務(wù)器端Go程序?qū)﹂L短鏈接的處理及運(yùn)行參數(shù)的保存,這里針對(duì)使用Go語言編寫的Socket服務(wù)器進(jìn)行實(shí)例說明,需要的朋友可以參考下2016-03-03
Golang 實(shí)現(xiàn)插入排序的方法示例(2種)
這篇文章主要介紹了Golang 實(shí)現(xiàn)插入排序的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作
這篇文章主要介紹了Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Go結(jié)合Gin導(dǎo)出Mysql數(shù)據(jù)到Excel表格
本文主要介紹了Go結(jié)合Gin導(dǎo)出Mysql數(shù)據(jù)到Excel表格,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08

