This repository has been archived on 2026-05-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
obsidian/金山办公作业/Week06/bcrypt成本因子.md
T

108 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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安全]] - 密码安全存储