fix: P0-04 prevent password reset code replay attack
ResetPasswordByPhone and ResetPassword now immediately consume (delete) the verification code/token after successful validation, before proceeding with password reset. This prevents replay attacks where the same code could be used multiple times. Security fix:验证码/Token验证通过后立即删除,防止Replay攻击
This commit is contained in:
@@ -113,6 +113,12 @@ func (s *PasswordResetService) ResetPassword(ctx context.Context, token, newPass
|
||||
return errors.New("重置Token数据异常")
|
||||
}
|
||||
|
||||
// 安全修复: 验证通过后立即删除Token,防止Replay攻击
|
||||
// Token消耗后立即失效,避免密码重置被重复触发
|
||||
if err := s.cache.Delete(ctx, cacheKey); err != nil {
|
||||
return fmt.Errorf("清理重置Token失败: %w", err)
|
||||
}
|
||||
|
||||
user, err := s.userRepo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
return errors.New("用户不存在")
|
||||
@@ -122,9 +128,6 @@ func (s *PasswordResetService) ResetPassword(ctx context.Context, token, newPass
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.cache.Delete(ctx, cacheKey); err != nil {
|
||||
return fmt.Errorf("清理重置Token失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -229,6 +232,10 @@ func (s *PasswordResetService) ResetPasswordByPhone(ctx context.Context, req *Re
|
||||
return errors.New("验证码不正确")
|
||||
}
|
||||
|
||||
// 安全修复: 验证通过后立即删除验证码,防止Replay攻击
|
||||
// 在密码重置完成前消耗验证码,确保同一验证码只能使用一次
|
||||
s.cache.Delete(ctx, codeKey)
|
||||
|
||||
// 获取用户ID
|
||||
cacheKey := fmt.Sprintf("pwd_reset_sms:%s", req.Phone)
|
||||
val, ok := s.cache.Get(ctx, cacheKey)
|
||||
@@ -241,6 +248,9 @@ func (s *PasswordResetService) ResetPasswordByPhone(ctx context.Context, req *Re
|
||||
return errors.New("验证码数据异常")
|
||||
}
|
||||
|
||||
// 安全修复: 立即删除手机->用户ID映射,防止重复使用
|
||||
s.cache.Delete(ctx, cacheKey)
|
||||
|
||||
user, err := s.userRepo.GetByID(ctx, userID)
|
||||
if err != nil {
|
||||
return errors.New("用户不存在")
|
||||
@@ -250,10 +260,6 @@ func (s *PasswordResetService) ResetPasswordByPhone(ctx context.Context, req *Re
|
||||
return err
|
||||
}
|
||||
|
||||
// 清理验证码
|
||||
s.cache.Delete(ctx, codeKey)
|
||||
s.cache.Delete(ctx, cacheKey)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user