From 1c6974ca68a5c6397dcf8cba32fa9c1127acc94f Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 18 Jun 2026 13:29:55 +0800 Subject: [PATCH] fix(auth): run dummy Argon2 verify for non-existent users to prevent timing enumeration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户不存在时执行一次固定合法哈希的 verify(必然失败),抹平与「密码错误」 路径的时序差,防止通过响应时间枚举账号(L2)。dummy 哈希走 spawn_blocking, 与真实校验路径耗时一致;响应消息保持一致。 --- src/api/auth.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/api/auth.rs b/src/api/auth.rs index 956b040..81ac3a3 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -201,6 +201,16 @@ pub async fn login(username: String, password: String) -> Result row, Ok(None) => { + // 用户不存在时也执行一次 Argon2 verify,抹平「用户不存在」与 + // 「密码错误」的响应时序差,防止通过响应时间枚举账号(L2)。 + // 用固定合法哈希做 verify(必然失败),耗时与真实校验一致。 + const DUMMY_HASH: &str = + "$argon2id$v=19$m=19456,t=2,p=1$j3rNaAXzdExYaL94WBWtfg$n1S75LUQKaYJwaRl5bkFF/f/N1tLfRYR/7TuQxKP94c"; + let dummy_pw = password.clone(); + let _ = tokio::task::spawn_blocking(move || { + crate::auth::password::verify_password(&dummy_pw, DUMMY_HASH) + }) + .await; return Ok(AuthResponse { success: false, message: "Invalid credentials".to_string(),