Argon2id
Argon2id 是面向 password hashing / password-based key derivation 的 memory-hard KDF,结合 Argon2i 与 Argon2d 的访问模式,在实际认证场景中兼顾 side-channel 与 GPU/ASIC 抵抗;安全参数由 memory、iterations 和 parallelism 共同决定。
[!info] related notes
- 所属 MOC: 安全 MOC
- Password Storage: Password Storage & Verification
- Salt/Pepper: Salt vs Pepper
- 对比: PBKDF2, bcrypt
- 上位概念: Password-Based KDF
Argon2id
一句话定义
Argon2id 是现代 password-hashing / password-based KDF。
它的核心不是“多算几次 hash”,而是:
同时消耗 CPU 时间和显著 memory,让大规模 GPU/ASIC password guessing 更昂贵。
Argon2 家族
Argon2 有三个主要变体:
- Argon2d;
- Argon2i;
- Argon2id。
Argon2d
更偏 data-dependent memory access。
对 GPU cracking 有优势,但 side-channel 场景更敏感。
Argon2i
memory access 更 data-independent。
更偏 side-channel resistance。
Argon2id
组合两种策略。
实际 password hashing 通常优先 Argon2id。
RFC 9106 在不确定具体 threat model 时也推荐 Argon2id。
三个核心参数
m:Memory Cost
使用多少内存。
例如:
19 MiB
64 MiB
1 GiB
更高 memory cost 会提高 attacker 大规模并行猜测的硬件成本。
t:Time / Passes
算法对 memory 执行多少轮/pass。
更高 t 增加 CPU/time cost。
p:Parallelism
控制 lane / parallelism。
它影响:
- latency;
- CPU usage;
- implementation behavior。
不能简单把 p 越大理解成“越安全”。
Salt
Argon2 password hashing 需要 unique salt。
RFC 9106 推荐 password hashing 使用 16-byte salt。
Salt:
- 可公开;
- 与 hash 一起存;
- 主要防止预计算和跨账号复用。
详见 Salt vs Pepper。
Password Hashing vs Key Derivation
Argon2id 可以用于:
Password Verifier
password
→ Argon2id
→ stored verifier
Password-Derived Key
password
→ Argon2id
→ encryption key material
虽然算法相同,但系统目标不同。
登录系统通常只需要 verify yes/no;本地保险库可能需要实际派生 encryption key。
参数不是永恒常数
RFC 9106 给出了强参数建议,例如:
- 2 GiB / t=1 / p=4;
- memory-constrained 场景 64 MiB / t=3 / p=4。
OWASP 面向 Web application 的当前最低基线更保守,例如:
- 19 MiB / t=2 / p=1;
- 或其他等价 trade-off。
这些数字不是互相矛盾,而是:
不同 deployment budget 下的防御基线。
真正参数应根据:
- server RAM;
- login concurrency;
- latency budget;
- attacker economics;
benchmark 后确定。
为什么 Memory-Hard
如果算法主要只消耗 CPU:
GPU / ASIC
→ massive parallel guesses
仍可能很便宜。
Memory-hard function 迫使每个并行 guess 也占用大量 memory bandwidth/capacity。
这提高大规模 cracking 的 hardware cost。
PHC String
成熟 Argon2 implementation 通常会输出自描述字符串,例如:
$argon2id$v=19$m=…,t=…,p=…$salt$hash
它保存:
- algorithm;
- version;
- parameters;
- salt;
- output。
这样 verifier 可以根据 stored value 自动恢复参数。
Parameter Upgrade
登录验证时:
stored parameters old → verify successful → current policy stronger → rehash password → update stored verifier
这比强迫全体用户立即重置密码更平滑。
DoS Trade-off
Memory hardness 同样会消耗合法服务器 memory。
例如一个 endpoint 同时处理 100 个高内存 Argon2 request,可能产生很大 RAM pressure。
因此必须结合:
- rate limiting;
- concurrency limit;
- benchmark;
- overload protection。
安全参数不能只追求“越大越好”。
Argon2id vs bcrypt
Argon2id:
- 显式 memory-hard;
- 参数维度更丰富;
- 现代优先选择。
bcrypt:
- 历史成熟;
- 主要 CPU cost;
- 有 72-byte password input 限制;
- 很多 legacy system 仍使用。
新系统若平台支持 Argon2id,一般不需要仅因为 bcrypt 更熟悉而优先 bcrypt。
Argon2id vs PBKDF2
PBKDF2:
- 主要依赖 iteration count;
- 广泛支持;
- 有 FIPS-validated implementation 生态;
- memory hardness 较弱。
Argon2id:
- memory-hard;
- 更适合现代 password cracking threat model。
但合规环境可能要求 PBKDF2。
常见错误
只调 t,不看 memory
会失去 Argon2 的核心 memory-hard 优势。
所有用户共用 salt
错误。每个 verifier 应有独立 salt。
参数写死十年不变
hardware 进步后 attacker 成本会持续下降。
为追求安全把 memory 调到服务无法承载
会制造 DoS 风险。
学习检查
- Argon2id 与普通快速 hash 最大的结构差异是什么?
- m、t、p 分别控制什么?
- Argon2id 为什么是 i/d 的折中?
- RFC 9106 与 OWASP 参数为什么会看起来不同?
- memory-hard 为什么能提高 GPU/ASIC cracking 成本?
- PHC string 为什么适合长期参数迁移?
- 为什么 Argon2 参数必须和 login concurrency 一起 benchmark?