vault backup: 2026-04-25 16:06:25
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
---
|
||||
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安全]] - 密码安全存储
|
||||
Reference in New Issue
Block a user