跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

golang用户密码怎么加密

应直接使用 bcrypt.GenerateFromPassword 和 bcrypt.CompareHashAndPassword 处理密码,明文需转 []byte 且长度≤72字节,cost 推荐 bcrypt.DefaultCost(当前为12),哈希值存取须用 string() 转换并校验长度为60、前缀为 $2b$。 直接用
bcrypt.GenerateFromPassword
和
bcrypt.CompareHashAndPassword
,别碰 AES、SHA256 或手写加盐逻辑。bcrypt 是密码哈希,不是加密——它不可逆,专为存密码设计;用错类型或参数,登录就静默失败。 明文密码传进去前必须转
[]byte
且 ≤ 72 字节 Go 的
bcrypt.GenerateFromPassword
第一个参数强制要求
[]byte
,传
string
直接编译报错。更隐蔽的问题是:UTF-8 编码后超 72 字节的部分会被静默丢弃,导致 "hello世界123..." 和它截断后的哈希值完全一样。 注册/登录入口必须校验:
if len([]byte(pwd)) 72 { return errors.New("password length must be 8–72 bytes") }
中文、emoji、全角符号都算字节,不是字符数;前端限制可被绕过,服务端校验不可省 别依赖
utf8.RuneCountInString
判长度——它数的是 rune,不是字节
cost
参数别硬写数字,优先用
bcrypt.DefaultCost
截至 2026 年 4 月,
bcrypt.DefaultCost
值为 12,对应单次哈希耗时约 150–250ms(主流云服务器),平衡了暴力破解成本与接口延迟。设成 10 太弱,GPU 几秒跑千万次;设成 14+ 可能单次超 1s,高并发下 goroutine 积压、HTTP 超时频发。 开发/测试环境用
cost=4
加速?可以,但必须和生产配置隔离——否则压测看不出真实延迟 从配置读取
cost
后,务必做范围校验:
if cost 31 { return errors.New("invalid bcrypt cost") }
迁移旧用户时,若 DB 里存的是
$2a$
开头的哈希,需兼容处理,不能直接 panic 哈希值存数据库必须用
string(hashed)
,字段至少
VARCHAR(255)
bcrypt.GenerateFromPassword
返回的是
[]byte
,但内容是 ASCII 文本(如
$2b$12$...
),固定约 60 字节。直接存
[]byte
到数据库,读出来大概率乱码或 decode 失败。 正确做法:
hashedStr := string(hashed)
,再存进数据库 MySQL 字段类型用
VARCHAR(255)
,PostgreSQL 推荐
TEXT
;
VARCHAR(50)
会截断,后续所有
CompareHashAndPassword
都返回
bcrypt.ErrMismatch
从 DB 读出后,先
strings.TrimSpace()
再传给比对函数——空格、BOM、换行都会让校验失败 调试时直接打长度:
fmt.Println(len(hashStr))
,不是 60 就立刻查源头(入库逻辑 or ORM 自动 trim)
CompareHashAndPassword
的调用顺序和前置检查不能漏 这个函数防时序攻击,但不帮你做任何业务逻辑判断。参数顺序反了、传空密码、哈希字段为空,它都可能返回
nil
或错误,但行为不一致。 立即学习 “ go语言免费学习笔记(深入) ”; 参数顺序必须是:
bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(inputPwd))
,顺序反了会 panic 调用前显式判空:
if len(inputPwd) == 0 { return errors.New("empty password") }
DB 查询结果为
nil
或
user.PasswordHash == ""
,应直接拒绝,别进比对流程 错误统一返回泛化提示(如 "invalid credentials"),日志中记录请求 ID + 哈希前缀即可,别打明文密码 真正容易被忽略的点是:哈希值在整条链路中是否被意外修改——从入库、JSON 序列化、ORM 映射、到读出比对,任何一个环节加空格、截断、base64 编码、或用了错误的字符集转换,都会让
CompareHashAndPassword
静默失败。调试时第一反应不该是“算法写错了”,而是先确认
len(hashStr) == 60
且开头是
$2b$
。

相关文章