--- tags: [go, security, bcrypt, password-hashing, cost-factor] create time: 2026-04-25 14:45 --- # bcrypt 成本因子(Cost Factor)详解 ## 概述 成本因子是 bcrypt 算法的核心参数,控制哈希计算的"难度"。它是平衡安全性和性能的关键旋钮。 ## 什么是成本因子? bcrypt 不是做一次哈希就完事,而是通过 **多次迭代** 来增加暴力破解的计算成本。成本因子(cost)就是这个迭代次数的对数指数: ``` 实际迭代次数 = 2^cost ``` 所以在 Go 中: ```go import "golang.org/x/crypto/bcrypt" // bcrypt.DefaultCost = 10 → 2^10 = 1024 次迭代 hash, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) ``` ## 不同成本因子的对比 | 成本值 | 迭代次数 | 单次哈希耗时 | 适用场景 | |--------|---------|------------|---------| | 4 | 16 | ~1ms | 本地开发、测试 | | 8 | 256 | ~50ms | 低流量内部系统 | | **10** | 1,024 | ~100-300ms | **生产环境默认** | | 12 | 4,096 | ~500ms | 高安全需求 | | 14 | 16,384 | ~2s | 极低频登录场景 | > 💡 **想一想**:成本因子是不是越高越好?为什么? > > 答案:不是。成本越高,合法用户登录时服务器也要做同等次数的计算。过高的成本会导致登录延迟,影响用户体验,也给服务器带来不必要的负载。 ## 如何选择合适的成本? ### 选择原则 ``` 目标:让单次哈希耗时在 100ms ~ 300ms 之间 ``` 这个区间意味着: - **对合法用户**:几乎无感,登录流畅 - **对攻击者**:暴力破解速度被大幅压制(每秒只能尝试 3~10 次) ### 调整方式 ```go // 生产环境手动调高 hash, _ := bcrypt.GenerateFromPassword([]byte(pwd), 12) // 也可以手动降低(仅开发环境) hash, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.MinCost) // MinCost = 4 ``` ## 成本因子的"升级陷阱" 一个容易被忽视的问题:当硬件变快后,原来合适的成本因子会变得不够安全。 ```go // 2024 年的机器比 2018 年快很多 // 当年 cost=10 是 200ms,现在可能只要 80ms // 解决方案:用户登录时检查并升级哈希 func Login(username, password string) error { user := db.GetUser(username) bcrypt.CompareHashAndPassword(user.Hash, []byte(password)) // 检测当前哈希的成本是否偏低 currentCost, _ := bcrypt.Cost(user.Hash) if currentCost < bcrypt.DefaultCost { // 用更高的成本重新哈希并保存 newHash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) db.UpdateHash(username, newHash) } } ``` > 💡 **想一想**:为什么要在登录时"顺便"升级哈希,而不是批量扫描全量用户? > > 答案:惰性升级(lazy upgrade)避免一次性计算压力过大,且只升级活跃用户的哈希,不活跃用户的旧哈希影响较小。 ## 最佳实践 ✅ **推荐** - 生产环境默认 `bcrypt.DefaultCost`(10) - 定期评估并逐步提升成本因子 - 登录时惰性升级低于最低成本的哈希 ❌ **避免** - 在生产环境使用 `< 10` 的成本 - 为每个用户设置不同的成本(增加复杂度且收益有限) - 为了追求极致安全而盲目调高到 14+ ## 关联笔记 - [[金山办公作业/Week06/登录安全流程]] - 登录安全全流程 - [[CS/DB/SQL安全]] - 密码安全存储