我在 Rust 中使用这个 Argon2 库进行密码哈希处理:
https://docs.rs/argon2/latest/argon2/
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let password_bytes = form.password.as_bytes();
let password_hash = argon2.hash_password(&password_bytes, &salt).unwrap().to_string();
println!("password_hash: {}",password_hash);
let parsed_hash = PasswordHash::new(&password_hash).unwrap();
if Argon2::default().verify_password(&password_bytes, &parsed_hash).is_ok() {
println!("Valid!");
}
生成的结果password_hash
如下:
$argon2id$v=19$m=19456,t=2,p=1$UWyFFxDMETxLo1q7BFjIEQ$i3MwCW0H7fZjFG7hMwKAPZgWs4hjo/foEUCwLsqp9uY
它似乎总是带有前缀$argon2id$v=19$m=19456,t=2,p=1$
我可以在将其存储到数据库之前删除该前缀以节省空间吗?然后在验证之前对其进行硬编码以添加它?
这些东西意味着什么?
它会一直都一样吗?
现代密码哈希算法包含“成本参数”,它们以性能和安全性为代价——简单地说,你希望验证哈希的速度足够慢,以至于攻击者无法尝试大量可能的密码,但又要足够快,以至于合法用户不会认为你的应用程序被破坏了。
为了在输入正确密码时生成匹配的哈希值,您需要知道用于生成存储哈希值的确切参数。正如您所说,您可以硬编码这些参数,但这意味着您永远无法更改它们- 特别是,随着计算机速度越来越快,您希望哈希值变慢。
因此,常见的做法是将使用的参数与每个哈希一起存储;这样,如果您将它们更改为新哈希,您仍然可以验证旧哈希。一些库还允许您在用户登录时检查存储的哈希是否使用参数的最新值 - 当您拥有正确的密码时,您可以保存一个新的、更安全的哈希。
同样,有时也会发现哈希算法被破解,或者变得太容易被攻击者暴力破解。这时,您可能希望从 Argon2 改用完全不同的算法。同样,您需要知道您存储的哈希中哪些使用的是 Argon2,哪些使用的是新算法,因此常见的做法是在哈希的最开始就指明所使用的算法。
对于 Argon2,这些参数的格式实际上是已发布标准的一部分,因此Argon2 的所有实现都将生成并期望这些精确的前缀。虽然你可以删除它们,但这样做实际上几乎没有什么好处,而且会有很多损失。
至于参数的实际含义,您可以在链接的 Rust 文档中找到简要概述,特别是在结构中
argon2::Params
:m_cost
:以 1 KiB 块为单位的内存大小。介于8*p_cost
和之间(2^32)-1
。t_cost
:迭代次数。介于1
和之间(2^32)-1
p_cost
:并行度。介于1
和之间(2^24)-1
。