不喜欢广告? 无广告 今天

bcrypt 用于密码哈希 为何仅靠加密不够

发布日期
bcrypt 用于密码哈希:为何仅靠加密不够 1
广告 移除?

如果你使用AES、RSA,甚至SHA-256来存储用户密码,那你是在做错事。不是轻微的错误——而是根本性的错误。这是网络开发中最常见的安全错误,而它的解决方案很简单:使用像bcrypt这样的专用密码哈希函数。

下面将解释其重要性、bcrypt的工作原理以及生产环境下的代码示例。

为何密码需要特殊处理

大多数加密操作都是为了 可逆或快速。加密是为可逆而设计的——这是它的全部目的。SHA-256和MD5是快速的,每秒可处理数十亿字节。这两个特性对密码来说都是灾难性的。

当攻击者获取你的数据库时,他们就能获取你的密码哈希值。对于加密,如果他们找到了密钥,就能解密所有内容。而对于像MD5或SHA-256这样的快速哈希,他们可以使用GPU加速的暴力破解攻击——现代硬件每秒可测试 数百亿 个MD5哈希值。你的“复杂”密码几分钟内就会被破解。

密码需要具备:

  1. 不可逆 ——即使拥有密钥或算法,也无法还原明文
  2. 计算速度慢 ——刻意的缓慢使暴力破解变得不切实际
  3. 每个用户唯一 ——相同的密码必须生成不同的哈希值

bcrypt 满足所有这三个要求。通用哈希函数和加密算法均不满足。

哈希、加密与密码哈希的区别

这些不能互换:

方法可逆?快速?适合密码安全?
加密(AES,RSA)是——拥有密钥时是的
快速哈希(MD5,SHA-256)是(设计如此)
密码哈希(bcrypt,Argon2id)否(设计如此)是的

加密的可逆性是致命缺陷:一旦密钥泄露,所有密码都将暴露。快速哈希同样致命:速度使得暴力破解成为可能。密码哈希函数被设计为缓慢——而这正是其目的所在。

bcrypt 的工作原理

bcrypt 于1999年由Niels Provos和David Mazières设计,它有三项关键功能:

1. 加盐。 在哈希之前,bcrypt 生成一个随机的盐(16字节),并将其包含在哈希输出中。即使两个用户拥有相同的密码,它们的哈希值也不同。这完全抵御了预计算彩虹表攻击。

2. 工作因子(成本)。 bcrypt 接受一个成本参数(通常为10到14)。每次递增都会使计算时间翻倍。在成本为12时,哈希操作在现代硬件上大约需要250至400毫秒。这对于登录请求来说几乎不可察觉地缓慢——但将十亿次尝试的暴力破解变成了长达数十年的操作。

3. 输出是自包含的。 一个bcrypt哈希看起来像 $2b$12$... ,并编码了算法版本、成本因子、盐和哈希值。你不需要单独的盐字段。只需存储整个字符串。

生产代码:Node.js 和 Python

Node.js(bcryptjs 或 bcrypt)

const bcrypt = require('bcrypt');

const SALT_ROUNDS = 12;

// Hash a password
async function hashPassword(plaintext) {
  return bcrypt.hash(plaintext, SALT_ROUNDS);
}

// Verify a password against a stored hash
async function verifyPassword(plaintext, storedHash) {
  return bcrypt.compare(plaintext, storedHash);
}

// Usage
const hash = await hashPassword('hunter2');
// Store `hash` in your database

const isValid = await verifyPassword('hunter2', hash);
// true

Python(bcrypt)

import bcrypt

COST = 12

def hash_password(plaintext: str) -> bytes:
    salt = bcrypt.gensalt(rounds=COST)
    return bcrypt.hashpw(plaintext.encode('utf-8'), salt)

def verify_password(plaintext: str, stored_hash: bytes) -> bool:
    return bcrypt.checkpw(plaintext.encode('utf-8'), stored_hash)

# Usage
hashed = hash_password('hunter2')
# Store hashed in your database

is_valid = verify_password('hunter2', hashed)
# True

存储完整的哈希字符串。永远不要存储明文,永远不要单独存储盐值,永远不要存储中间值。

选择工作因子

合适的工作因子取决于你的硬件。目标是让每次哈希操作在你的生产服务器上耗时 200–500毫秒 。这既保证了良好的用户体验,又足以让攻击者感到困扰。

当前建议: 成本12 作为最低标准, 14 对于高价值账户(管理员、财务账户)。在你的实际硬件上进行基准测试:

// Node.js: benchmark different cost factors
const bcrypt = require('bcrypt');

for (let cost = 10; cost <= 14; cost++) {
  const start = Date.now();
  await bcrypt.hash('benchmark', cost);
  console.log(`Cost ${cost}: ${Date.now() - start}ms`);
}

如果成本12耗时少于100毫秒,就提高它。如果成本14耗时超过1000毫秒,就降低到13。每年重新评估一次——硬件会变快,你的成本因子也应随之调整。

你可以使用 IO Tools bcrypt 哈希生成器.

bcrypt 与 Argon2id 与 scrypt 的对比

bcrypt 经过实战检验且广泛支持。但它有一个局限性:它不是内存密集型的。拥有专用硬件(ASIC或FPGA)的攻击者可以比内存密集型算法更高效地并行化攻击。

Algorithm内存密集型抗并行攻击推荐
bcrypt部分良好默认选项;成本≥12
scrypt是的部分优于bcrypt,工具支持较少
Argon2id是的是的推荐用于新项目

对于新项目: 使用Argon2id。它赢得了2015年的密码哈希竞赛,是内存密集型的,能抵抗GPU和ASIC攻击,并已被OWASP列为推荐方案。其API与bcrypt几乎相同。

对于现有项目: 如果你已经使用bcrypt并且成本因子合理,迁移并不紧急。可以在下一次重大重构中进行。

常见的实现错误

对哈希值再次哈希。 一些开发者会在客户端对密码进行哈希,然后再在服务器端对哈希值进行二次哈希。客户端的哈希值变成了“密码”。你现在是在哈希一个固定长度的十六进制字符串,而不是一个用户选择的密码——双重哈希不会带来任何好处,也不会带来任何收益,反而引入了混淆。

72字节截断问题。 bcrypt 会静默忽略超过72字节的内容。一个100字符的密码和一个前72字符相同的72字符密码在bcrypt中是相同的。如果用户设置了很长的密码,这将导致无声的安全降级。缓解措施:在传递给bcrypt之前,先用SHA-256进行预哈希——但前提是你要完全理解其影响,并清晰地记录说明。

工作因子过弱。 成本10在2011年是合理的。到2026年,至少应使用成本12。如果你现有的记录使用成本10,可以透明升级:在登录成功后,用新成本重新哈希已验证的密码,并存储更新后的哈希值。

异步操作很重要。 bcrypt 是CPU密集型的。在Node.js中,始终使用异步API(如上所示),以避免阻塞事件循环。在Node服务器中使用同步bcrypt会使所有其他请求等待。

从MD5/SHA迁移到bcrypt

你无法在没有原始明文的情况下重新哈希。但你可以进行机会性迁移:

  1. 添加一个 password_hash 列,与旧 password_md5
  2. 在登录成功时(当你拥有明文密码),使用bcrypt对其进行哈希,并存储在 password_hash,清除旧列
  3. 在迁移期间,未登录的用户可以被强制重置密码
  4. 一旦 password_md5 对所有用户为空,删除该列

这是标准做法,无需停机。

底线

加密适用于你需要检索的数据。哈希适用于你需要验证的数据。密码应被验证而非检索——这意味着加密是错误的工具。

bcrypt 提供了加盐、可配置的缓慢计算和自包含的哈希格式。它已经为25年提供了正确的解决方案。使用成本12或更高的值,新项目使用Argon2id,并尽快迁移到bcrypt,同时淘汰MD5和SHA-256。

搞错这一点不是假设风险。数据库一旦被泄露,使用bcrypt哈希的密码在计算上几乎无法被破解。而MD5哈希可以在一夜之间被破解。

想要享受无广告的体验吗? 立即无广告

安装我们的扩展

将 IO 工具添加到您最喜欢的浏览器,以便即时访问和更快地搜索

添加 Chrome 扩展程序 添加 边缘延伸 添加 Firefox 扩展 添加 Opera 扩展

记分板已到达!

记分板 是一种有趣的跟踪您游戏的方式,所有数据都存储在您的浏览器中。更多功能即将推出!

广告 移除?
广告 移除?
广告 移除?

新闻角 包含技术亮点

参与其中

帮助我们继续提供有价值的免费工具

给我买杯咖啡
广告 移除?