ASP.NET Razor Pages如何通过响应时间模糊防范计时攻击?
防范Razor Pages重发验证邮件接口的计时攻击方案
核心思路
计时攻击的本质是响应时间差异泄露敏感信息,所以核心目标是消除「用户存在且未验证」与「用户不存在/已验证」两种场景的执行耗时差,可从业务逻辑或全局中间件两个层面实现。
方案一:业务逻辑层面抹平时间差(最直接有效)
无需额外依赖,直接修改现有代码,让两种分支的执行耗时尽可能一致:
public async Task<IActionResult> OnPost() { // 预执行耗时操作的模拟流程,确保无论用户状态如何都走一遍相同耗时步骤 var dummyUrl = await GenerateVerificationUrlAsync(new User()); var dummyEmailContent = await _emailRenderer.RenderConformationEmail(dummyUrl); // 正常业务逻辑 User user = await _manager.FindUserByEmailAsync(InputModel.Email); if (!(user is null || user.EmailConfirmed)) { string confirmationUrl = await GenerateVerificationUrlAsync(user); await _emailSender.SendAsync(user.Email, "Verify Email", await _emailRenderer.RenderConformationEmail(confirmationUrl)); } // 统一返回相同提示,绝不区分场景 // 添加模型错误提示用户验证邮件已发送 return Page(); }
- 原理:不管用户是否符合发送条件,都先执行一遍生成链接、渲染邮件的模拟操作,让两种分支的总耗时趋近一致,从根源上消除时间差。
- 注意:如果
GenerateVerificationUrlAsync依赖真实用户的ID等信息,可生成临时假用户对象,或直接用Task.Delay(xxx)模拟对应耗时。
方案二:全局响应延迟中间件(辅助补充)
如果想在全局层面给敏感接口添加随机延迟,进一步抹平细微时间差异,可编写简单中间件:
public class ResponseDelayMiddleware { private readonly RequestDelegate _next; private readonly Random _random; private readonly int _minDelayMs; private readonly int _maxDelayMs; public ResponseDelayMiddleware(RequestDelegate next, IConfiguration configuration) { _next = next; _random = new Random(); // 可通过配置文件调整延迟范围,示例为100-300ms _minDelayMs = configuration.GetValue<int>("ResponseDelay:MinMs", 100); _maxDelayMs = configuration.GetValue<int>("ResponseDelay:MaxMs", 300); } public async Task InvokeAsync(HttpContext context) { // 先处理请求业务逻辑 await _next(context); // 仅对目标POST接口添加延迟,避免影响普通页面加载体验 if (context.Request.Method == HttpMethods.Post && context.Request.Path.StartsWithSegments("/Account/ResendVerification")) { var delayMs = _random.Next(_minDelayMs, _maxDelayMs); await Task.Delay(delayMs); } } } // 扩展方法用于注册中间件 public static class ResponseDelayMiddlewareExtensions { public static IApplicationBuilder UseResponseDelay(this IApplicationBuilder builder) { return builder.UseMiddleware<ResponseDelayMiddleware>(); } }
- 使用方式:在
Program.cs的app.UseRouting()之后添加app.UseResponseDelay(); - 注意:延迟范围不宜过大,避免影响用户体验;建议仅针对敏感接口添加,不要全局覆盖所有请求。
额外优化建议
- 统一提示文案:所有场景返回完全相同的提示文本,绝不泄露用户是否存在、是否已验证等信息。
- 请求限流:配合ASP.NET Core自带的Rate Limiting限流组件,限制单位时间内的请求次数,增加攻击者枚举难度。
内容的提问来源于stack exchange,提问作者Doshorte Dovencio
相关产品推荐
相关产品推荐

