SHA-256 vs bcrypt vs Argon2 - 开发者哈希算法完全比较
了解为什么不应该使用SHA-256存储密码、bcrypt和Argon2的区别,以及2026年推荐的哈希策略。
Toolypet Team
Development Team
SHA-256 vs bcrypt vs Argon2:什么时候使用什么?
"用SHA-256哈希密码然后存储应该是安全的,对吧?"
很多开发者问这个问题。结论是:密码不应该使用SHA-256。
本指南解释哈希算法的区别以及每种情况下的正确选择。
哈希 vs 加密:基本概念
哈希(Hashing)
输入 → 哈希函数 → 固定长度输出(不可逆)
"password" → SHA-256 → "5e884898da28047d..."
- 单向:无法恢复原始数据
- 确定性:相同输入 = 相同输出
- 固定长度:输出大小与输入大小无关
加密(Encryption)
输入 + 密钥 → 加密 → 密文 → 解密 + 密钥 → 原始数据
"password" + key → AES → "Xyz..." → AES + key → "password"
- 双向:可以用密钥恢复原始数据
- 密钥依赖:没有密钥无法解密
密码存储应使用哈希。 不需要知道原始数据——只需比较输入值和哈希。
哈希算法分类
快速哈希(Fast Hash)
| 算法 | 输出长度 | 速度 | 用途 |
|---|---|---|---|
| MD5 | 128位 | 非常快 | ❌ 禁止用于安全 |
| SHA-1 | 160位 | 快 | ❌ 禁止用于安全 |
| SHA-256 | 256位 | 快 | 文件完整性、数字签名 |
| SHA-512 | 512位 | 快 | 文件完整性、区块链 |
慢速哈希(Slow Hash / Password Hash)
| 算法 | 特点 | 2026推荐 |
|---|---|---|
| bcrypt | 时间可调(cost) | ✅ |
| scrypt | 内存密集型 | ✅ |
| Argon2 | 最新,OWASP第1位 | ✅✅ |
| PBKDF2 | 兼容性高 | ⚠️ 遗留 |
为什么不应该用SHA-256存储密码?
原因1:太快了
SHA-256是为速度而设计的。这对文件完整性检查是优点,但对密码存储是致命缺点。
现代GPU性能:
- MD5:每秒1800亿次哈希
- SHA-256:每秒100亿次哈希
- bcrypt(cost 12):每秒1000次哈希
即使是8字符的复杂密码,用SHA-256存储也可以在几分钟内被破解。
原因2:需要手动管理Salt
# ❌ 错误方法
hash = sha256(password)
# 问题:容易受到彩虹表攻击
# ⚠️ 改进了但仍不够
salt = generate_random_salt()
hash = sha256(salt + password)
# 问题:仍然太快
原因3:GPU加速漏洞
SHA-256很容易在GPU上并行处理。攻击者用几块游戏GPU就能以惊人的速度计算哈希。
bcrypt:27年验证的标准
工作原理
bcrypt(cost, salt, password) → hash
cost:计算迭代次数(2^cost)
salt:22字符随机字符串(自动生成)
为什么bcrypt安全?
- 故意很慢:通过cost factor控制速度
- 自动Salt:每次生成不同的哈希
- 内存密集型:难以GPU加速
Cost Factor指南(2026年)
| Cost | 哈希时间 | 推荐用途 |
|---|---|---|
| 10 | ~100ms | 开发/测试 |
| 12 | ~250ms | 一般Web应用(推荐) |
| 13-14 | ~500ms | 高安全需求 |
| 15+ | 1秒以上 | 特殊目的 |
代码示例
// Node.js with bcrypt
const bcrypt = require('bcrypt');
// 哈希(注册)
const hash = await bcrypt.hash(password, 12); // cost 12
// 验证(登录)
const isValid = await bcrypt.compare(inputPassword, storedHash);
# Python with bcrypt
import bcrypt
# 哈希
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
# 验证
is_valid = bcrypt.checkpw(input_password.encode(), stored_hash)
Argon2:下一代标准
什么是Argon2?
2015年密码哈希竞赛的获胜者。它是OWASP 2026年第1推荐的算法。
Argon2变体
| 变体 | 特点 | 推荐 |
|---|---|---|
| Argon2d | GPU攻击抵抗 | 侧信道脆弱 |
| Argon2i | 侧信道抵抗 | GPU攻击脆弱 |
| Argon2id | d + i混合 | ✅ 推荐 |
Argon2参数
Argon2id(memory, iterations, parallelism, password, salt)
- memory:内存使用量(KB)
- iterations:迭代次数
- parallelism:并行线程数
OWASP推荐设置(2026年)
最小设置:
- memory:64MB(65536 KB)
- iterations:3
- parallelism:4
高安全性:
- memory:256MB
- iterations:4
- parallelism:8
代码示例
// Node.js with argon2
const argon2 = require('argon2');
// 哈希
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536, // 64MB
timeCost: 3,
parallelism: 4
});
// 验证
const isValid = await argon2.verify(storedHash, inputPassword);
# Python with argon2-cffi
from argon2 import PasswordHasher
ph = PasswordHasher(
memory_cost=65536,
time_cost=3,
parallelism=4
)
# 哈希
hash = ph.hash(password)
# 验证
try:
ph.verify(stored_hash, input_password)
except VerifyMismatchError:
# 密码不匹配
bcrypt vs Argon2:选择哪个?
比较表
| 项目 | bcrypt | Argon2id |
|---|---|---|
| 年龄 | 1999年(27年) | 2015年(11年) |
| 验证 | 27年实战验证 | 学术验证完成 |
| 内存调整 | ❌ | ✅ |
| GPU抵抗 | ⚠️ 中等 | ✅ 强 |
| 库支持 | 所有语言 | 大多数语言 |
| OWASP排名 | 第2位 | 第1位 |
选择指南
选择bcrypt:
- 需要遗留系统兼容性
- 优先考虑验证的稳定性
- 偏好简单配置
选择Argon2id:
- 开始新项目
- 遵循最新安全标准
- 需要高GPU抵抗力
2026年推荐顺序(OWASP)
第1位:Argon2id
第2位:bcrypt
第3位:scrypt
第4位:PBKDF2(需要兼容性时)
何时使用SHA-256
SHA-256对于密码以外的用途是完美的。
适合的用途
| 用途 | 示例 |
|---|---|
| 文件完整性 | 下载验证、备份确认 |
| 数字签名 | JWT、证书 |
| 区块链 | 比特币挖矿 |
| 校验和 | 数据传输验证 |
| 哈希表 | (与HMAC一起)API密钥存储 |
代码示例
// 文件哈希(Node.js)
const crypto = require('crypto');
const fs = require('fs');
const fileBuffer = fs.readFileSync('file.zip');
const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
console.log(hash); // "a1b2c3d4..."
实际实施清单
密码存储
- 使用Argon2id或bcrypt
- 设置适当的work factor(250-500ms)
- 使用库自动salt生成
- 存储完整哈希结果(包括salt)
密码验证
- 使用时序攻击安全的比较函数
- 验证失败时响应时间一致
- 限制登录失败次数
迁移
- 逐步升级到新哈希
- 登录成功时用新算法重新哈希
- 使用前缀标识旧哈希
常见问题
Q1:如何处理用MD5存储的现有密码?
A:当用户登录时用新算法重新哈希。
// 登录成功时
if (hash.startsWith('$md5$')) {
// 用bcrypt重新哈希
const newHash = await bcrypt.hash(inputPassword, 12);
await updateUserHash(userId, newHash);
}
Q2:bcrypt的72字节限制是问题吗?
A:大多数密码在72字节以内。如果需要更长的输入,先用SHA-256哈希,然后应用bcrypt。
// 处理长密码
const prehash = crypto.createHash('sha256').update(password).digest('base64');
const finalHash = await bcrypt.hash(prehash, 12);
Q3:cost factor设置太高会不会导致DoS攻击漏洞?
A:是的。同时实施登录请求速率限制。250-500ms是适当的平衡点。
Q4:需要pepper吗?
A:pepper(应用级密钥)提供额外安全性,但不是必需的。仅salt就足够了。
Q5:可以使用在线哈希工具吗?
A:仅用于学习/测试目的。在生产环境中,必须在服务器端进行哈希。哈希生成器是安全的,因为它100%在客户端处理。
总结
| 用途 | 推荐算法 |
|---|---|
| 密码存储 | Argon2id > bcrypt |
| 文件完整性 | SHA-256 |
| 数字签名 | SHA-256 / SHA-512 |
| 遗留兼容 | bcrypt / PBKDF2 |
核心原则:
- 密码绝不使用快速哈希(SHA-256、MD5)
- bcrypt cost 12以上,Argon2 memory 64MB以上
- 使用库提供的自动salt生成
相关工具
| 工具 | 用途 |
|---|---|
| Hash Generator | 生成SHA-256、bcrypt哈希 |
| Password Generator | 生成强密码 |
关于作者
Toolypet Team
Development Team
The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.