Argon2 的三个参数怎么配

工具相关 ·

第一次配置 Argon2 时,面对 m、t、p 三个参数和一堆推荐值,很容易陷入「全都设大一点总没错」的思路。但 Argon2 的内存参数设得过大,会把服务器内存迅速吃光,攻击者甚至可以用大量登录请求把服务打挂。这三个参数各有分工,配法需要理解它们分别抵抗什么。

三个参数分别控制什么

Argon2 的编码串里会写出参数,形如 m=19456,t=2,p=1。三项含义如下。

m 是内存开销,单位 KiB。它决定算法在一次计算过程中需要占用多少内存。这是 Argon2 区别于 Bcrypt 的核心能力——Bcrypt 只消耗 CPU 时间,而 Argon2 会强制占用一大块内存。

t 是迭代次数,也就是时间开销。它控制对整个内存块做几遍压缩运算,增加单次计算的轮数。

p 是并行度,也就是可用的线程通道数。它决定计算能拆成几路并行执行,影响吞吐,但不改变总内存开销——内存是按 m 分配的,p 只是把这些内存分给几条通道。

还有一个 l 表示输出长度,通常用 32 字节(256 位)就够,不需要特别调整。

推荐的参数组合

业界有两个权威来源给出推荐值。

OWASP 的推荐是 m=19456(19 MiB)、t=2、p=1。这一组参数在普通服务器上单次校验约几十毫秒,是通用场景的稳妥选择,也是多数工具和库的默认值。

RFC 9106 给出了两套推荐。第一推荐是 m=2 GiB、t=1、p=4,安全性极高但需要大量内存;第二推荐是 m=64 MiB、t=3、p=4,属于折中方案。

实际项目里,建议从 OWASP 那组开始,然后按自己服务器的实测情况微调。

用耗时来确定最终值

与 Bcrypt 一样,Argon2 的参数也应当按目标耗时倒推,而不是照抄某个数字。目标是让单次校验落在 100 到 500 毫秒之间。

调整时有一个优先顺序:优先保证 m 足够大,再用 t 做微调。

原因在于,m 是抵抗显卡的关键。显卡的优势来自大量并行核心,而每个核心都需要独立的内存空间。当算法要求每个并行实例占用几十 MB 内存时,显卡能同时运行的实例数就受限于显存容量,攻击成本大幅上升。如果为了省内存把 m 压到很低(比如几 MiB),Argon2 就退化成了一个「慢一点的 SHA」,抗 GPU 的能力基本丧失。

如果服务器内存确实紧张,宁可降低 t 也要保住 m;只有在内存实在不够的情况下,才考虑把 m 压到 8 MiB 以下——但那时应该重新评估是否该用 Bcrypt 或 PBKDF2。

内存参数过高会怎样

m 设得过大有两个实际风险。

第一是并发问题。如果单次校验需要 2 GiB 内存,服务器同时只能处理一两个登录请求,第三个请求就会因为内存不足而失败或被排队。这在正常业务里是不可接受的。

第二是拒绝服务。攻击者只要发起大量登录请求,就能让服务器不断分配大块内存,很快耗尽资源。参数越大,攻击者需要的请求数越少,攻击越容易。

所以确定 m 之前,应该做两件事:压测单次校验的峰值内存占用,然后按「服务器可用内存 ÷ 单次占用」估算可承受的并发数。如果算出来的并发数低于业务峰值,就需要降低 m 或者限制登录接口的并发。

参数需要定期重新评估

和所有慢哈希一样,Argon2 的参数会随着硬件进步而逐渐变得不够用。今天需要 300 毫秒的计算,几年后可能只要 60 毫秒。

所以建议每隔几年重新做一次基准测试。升级参数时不需要让用户改密码——参数和盐都写在哈希串里,校验函数会读取串里的值。做法是保留旧哈希,在用户下次登录成功时用新参数重新计算并覆盖,逐步完成迁移。

检查清单

  • m 是内存开销(KiB),t 是迭代次数,p 是并行度,三者分工不同
  • p 只影响并行通道数,不改变总内存开销
  • OWASP 推荐 m=19456, t=2, p=1,可作为起点
  • 目标是单次校验耗时 100 到 500 毫秒,按服务器实测调整
  • 优先保证 m 足够大,内存紧张时宁可降低 t
  • 确定 m 前压测峰值内存,按可用内存估算可承受的并发数
  • 每隔几年重新评估参数,用登录时顺带升级的方式迁移
阅读 12