什么是速率限制
速率限制是保护Web应用程序和API免受恶意攻击和过度使用的一项关键技术。通过限制特定时间窗口内允许的请求数量,速率限制有助于防止分布式拒绝服务(DDoS)攻击和 API滥用。
中间件Microsoft.AspNetCore.RateLimiting提供限速中间件
速率限制算法
固定窗口算法(Fixed Window Algorithm)
固定窗口算法允许特定时间窗口内固定数量的请求。任何超出限制的后续请求都会受到限制。
代码示例
1 | builder.Services.AddRateLimiter(option => |
- PermitLimit表示在指定的时间窗口内允许的最大请求数
- Window表示在指定的时间窗口内
滑动窗口算法(Sliding Window Algorithm)
滑动窗口算法与固定窗口算法类似,滑动窗口算法是将时间窗口分割成段
代码示例
1 | builder.Services.AddRateLimiter(option => |
- Window: 定义了滑动窗口的持续时间,在此时间范围内请求将被计数并受到限制。
- SegmentsPerWindow:指定滑动窗口被分成的段数,它被设置为1,意味着滑动窗口不会被进一步划分为更小的段。
在使用滑动窗口算法进行速率限制的上下文中,“分段”是指将时间窗口划分为更小的间隔。每个片段代表整个时间窗口的一部分。
使用滑动窗口速率限制器时,时间窗口被分为多个段来跟踪和强制执行速率限制。段的数量决定了窗口内速率限制的粒度。
例如,如果您的时间窗口为 1 分钟并指定 2 段,则意味着时间窗口被分为两个相等的间隔,每个间隔为 30 秒。速率限制在每个段内单独应用,允许每个段一定数量的请求。
令牌桶算法(Token Bucket Algorithm)
令牌桶算法为每个请求分配令牌,并且仅当令牌可用时才允许处理,令牌以固定速率补充
代码示例
1 | builder.Services.AddRateLimiter(option => |
- TokenLimit:在任何给定时间可用的最大令牌(请求)数
- TokensPerPeriod:每个周期生成的令牌数量
- ReplenishmentPeriod:设置令牌生成的间隔时间,它决定重新生成令牌的频率
令牌桶算法通过为每个传入请求分配一个令牌来工作。如果令牌桶中有令牌可用,则允许请求并消耗令牌。如果令牌桶为空,表明已达到速率限制,请求将被拒绝或被限制。
通过以上配置,令牌桶限制器在1分钟内生成5个令牌但最多允许3次请求(令牌)。一旦达到令牌限制,任何其他请求都将受到速率限制。
并发算法(Concurrency Algorithm)
并发速率限制算法限制的是请求的并发执行数,而不是一个时间窗口内的请求总数。
示例代码
1 | builder.Services.AddRateLimiter(option => |
- PermitLimit表示允许同时(同一时间)请求的最大数量
- QueueLimit设置可以排队的最大请求数量
通过上述配置,并发限制器最多允许3个并发请求,如果达到限制,则最多可以对3个额外请求进行排队。任何超出许可和队列限制的请求都将受到速率限制。
实际运用
- 配置速率限制策略(参考上述速率限制算法)
- 启用速率限制中间件
1 | app.UseRateLimiter(); |
- 打开要应用速率限制的控制器文件,找到控制器类声明,在类声明上方添加属性 [EnableRateLimiting(“PolicyName”)] (”PolicyName”替换为要应用的速率限制策略的实际名称)
示例代码
1 | [ ] |
在上面的示例中,EnableRateLimiting属性应用于HomeController类,指定”tokenbucket”速率限制策略。
什么是AspNetCoreRateLimit
AspNetCoreRateLimit 是一个流行的开源库,用于在ASP.NET Core 应用程序中进行速率限制。该库允许您根据客户端IP地址、路由和HTTP方法定义速率限制规则,从而使您能够对应用程序的速率限制策略进行细粒度控制。
安装命令
1 | Install-Package AspNetCoreRateLimit |
配置
- 打开appsettings.json
- 添加以下配置
1 | "IpRateLimiting": { |
参数解析
- EnableEndpointRateLimiting:指定是否启用基于端点的速率限制
- StackBlockedRequests:决定是否将阻塞的请求堆叠起来供以后处理
- RealIPHeader:包含客户端真实IP地址的标头名称
- ClientIdHeader:包含客户端唯一标识符的标头名称
- HttpStatusCode:超出速率限制时返回的 HTTP 状态代码
- GeneralRules: 一组速率限制规则。
在此示例中方便测试,我们有一个适用于所有端点的规则 (*)。它将请求限制为每分钟3个,并提供超出配额时返回的消息。
实际运用
- 打开Program文件,添加以下代码
1 | var builder = WebApplication.CreateBuilder(args); |
上述代码实现了添加内存缓存,从appsettings.json读取IpRateLimitOptions配置并注册速率限制服务。把UseIpRateLimiting中间件添加到管道中,该中间件将处理我们端点的速率限制执行。
测试速率限制
假设我们有一个接口/api/customers要对其进行速率限制,如果超过每分钟 3个请求的配置限制,接口应该返回响应429 Too Many Requests。
尝试在一分钟内向接口发送多个请求/api/customers,正常结果应该会收到超出速率限制的响应
测试结果
正常结果
限速结果
限制每个接口的请求
在前面的示例中,我们使用通配符将速率限制规则应用于所有端点”*”。但是,我们还可以为各个端点定义特定的速率限制。要将速率限制应用于特定端点,修改appsettings.json文件中”GeneralRules”中的数组,如下所示:
1 | "GeneralRules": [ |