密码哈希算法怎么选择?

wen 网络安全 2

本文目录导读:

密码哈希算法怎么选择?

  1. 第一梯队:强烈推荐(现代、安全、首选)
  2. 第二梯队:仍然可用(经典、广泛支持、但已过时)
  3. 第三梯队:绝不要使用(危险)
  4. 核心参数最佳实践
  5. 总结决策(快速选择表)
  6. 如何确保正确实现

选择密码哈希算法是一个涉及安全性的关键决策,核心原则是:不要使用自己设计的算法,不要使用普通的快速哈希(如 MD5、SHA-1、SHA-256),而要使用专门为密码设计的、慢速且加盐的哈希算法。

以下是选择密码哈希算法的完整指南,按优先级从高到低排列:

第一梯队:强烈推荐(现代、安全、首选)

目前行业标准公认最安全、最推荐的算法只有两个:

  1. Argon2

    • 地位: 2015年密码哈希竞赛的获胜者,是目前最先进、最安全的密码哈希算法。
    • 特点: 它可以同时抵抗三种攻击
      • GPU/ASIC(专用集成电路)攻击:通过内存密集型设计,让硬件无法并行加速。
      • 时间-空间权衡攻击:通过CPU消耗和内存消耗的平衡性设计,让破解者无法通过牺牲内存来换取速度。
    • 变体: 主要用 Argon2id(混合模式,推荐),其次是 Argon2i(抗侧信道)和 Argon2d(抗GPU,但可能被侧信道攻击影响)。
    • 如何使用: 绝大多数现代密码库(如 libsodiumpasslibbcrypt 的高阶包装)都支持 Argon2,你只需要提供密码、盐(库自动生成)和参数(cost、memory、parallelism)。
  2. scrypt

    • 地位: 在 Argon2 出现之前,它是针对硬件攻击的最佳选择,现在虽然稍逊于 Argon2,但在正确实现时仍然非常安全。
    • 特点: 也是内存硬算法,强制消耗大量内存,从而大大增加定制硬件(ASIC)的破解成本。
    • 适用场景: 如果库不支持 Argon2(很少见),scrypt 是极好的替代品,许多加密货币钱包(如 Litecoin)使用它。

第二梯队:仍然可用(经典、广泛支持、但已过时)

如果因为技术限制(例如使用非常老旧的语言或框架,无法安装新库)无法使用 Argon2 或 scrypt,可以考虑以下算法。但请注意,它们不如第一梯队安全。

  1. bcrypt

    • 地位: 曾经的王者,目前仍被大量生产系统使用。
    • 特点: 基于 Blowfish 加密算法,慢速可调成本(cost factor)。
    • 缺点: 它不是内存硬的,因此可以被定制硬件(FPGA、ASIC)以相对较低的成本进行大规模破解,虽然比 MD5 慢很多,但和 Argon2/scrypt 相比,硬件加速的威胁要大得多。
    • 建议: 如果你必须选择 bcrypt,请将 cost factor 设置得尽可能高(在服务器可接受的延迟内,建议至少 10-12,例如成本因子为 12 时,单次哈希约需 250ms)。
  2. PBKDF2

    • 地位: 行业标准(RFC 2898),广泛使用在 WPA3、iOS/Android 密码管理等。
    • 特点: 简单、可调迭代次数。
    • 致命弱点: 纯粹依赖CPU,没有内存硬性要求,这意味着使用 GPU 或 ASIC 可以非常高效地并行破解,它比 bcrypt 更脆弱。
    • 建议: 除非你的平台只支持 PBKDF2(例如某些嵌入式系统、旧版PHP),否则尽量避免,如果必须用,将迭代次数设为极高(600,000次以上,这会使单次哈希达到数百毫秒级)。

第三梯队:绝不要使用(危险)

这些算法绝对不要用于存储用户密码:

  • MD5:已经被完全破解,可以极快地生成碰撞(不同密码相同哈希),并且速度极快,每秒可尝试数十亿次。
  • SHA-1:同样被攻破,速度极快,已不推荐用于任何安全场景。
  • SHA-256 / SHA-3系列:虽然它们是优良的通用哈希算法(用于校验文件完整性、数字签名等),但它们是为速度优化的,正是这个特性使它们极其不适合密码存储,攻击者可以用 GPU 在几小时内尝试所有8字符纯字母密码。
  • 不加盐的哈希:任何算法如果不加随机的盐,都会导致两个用户密码相同时哈希完全相同,极易被彩虹表攻击。

核心参数最佳实践

无论你选择 Argon2、scrypt 还是 bcrypt,都需要合理设置参数:

  1. 盐(Salt)

    • 必须由系统自动生成,使用高性能的随机数生成器(os.urandomSecureRandom)。
    • 长度至少16字节(128位)。
    • 每个用户每个密码都不同,并且存储在哈希值旁边(通常是哈希值的一部分)。
  2. 工作因子(Cost / Iterations)

    • 目标:你的生产服务器硬件上,单次哈希计算时间大约在 100ms - 300ms 之间(用户注册/登录时能接受这个延迟)。
    • 方法: 在部署前在你的服务器上进行基准测试,如果你选择 Argon2,调整 time_cost(时间/CPU成本)和 memory_cost(内存大小,64MB~128MB);对于 bcrypt,调整 cost 因子(如 12~14);对于 PBKDF2,调整迭代次数(如 几十万到几百万次)。
  3. 算法版本管理

    • 当未来更强的算法出现时,你需要能够在不破坏现有用户登录的情况下升级。
    • 策略: 在存储的哈希字符串中包含算法标识符$argon2id$v=19$m=65536,t=2,p=4$...$2y$12$...)。
    • 当用户登录时,检查所用的算法是否为当前最新,如果不是,使用新算法重新哈希并更新数据库(称为“密码哈希升级”)。

总结决策(快速选择表)

场景 推荐算法 理由
全新项目,无技术限制 Argon2 (Argon2id) 最安全,抗硬件攻击,有内存硬性要求。
需要兼容旧系统或库限制 scrypt 安全程度高,也是内存硬,但略逊于 Argon2。
必须使用经典库(如某些PHP/MySQL) bcrypt (成本因子 >=12) 比 PBKDF2 安全,但不如前两者。
唯一选择(嵌入式/极旧系统) PBKDF2 (迭代次数 >=60万) 安全性最低,但比不使用任何哈希好。
永远不要使用 MD5, SHA-1, SHA-256 太慢!不,是太快!**

如何确保正确实现

  • 使用成熟的库:永远不要自己写密码哈希代码,使用如下库:
    • Python: bcrypt, argon2-cffi, hashlib (内置PBKDF2)
    • Node.js: bcryptjs, argon2, crypto (内置 scrypt, PBKDF2)
    • Go: golang.org/x/crypto/bcrypt, argon2, scrypt
    • Ruby: bcrypt gem, argon2 gem
    • PHP: password_hash() (默认使用 bcrypt + 自动盐,8.0+ 可选 Argon2)
    • Java: Spring SecurityBCryptPasswordEncoder, Argon2PasswordEncoder

请记住:没有完美,只有更优,定期关注安全界的最新动态(比如几年后 Argon2 是否被攻破),并在可行时升级你的哈希策略。

抱歉,评论功能暂时关闭!