ASP.NET Core-请求频率限制(AspNetCoreRateLimit)

参考:
https://github.com/stefanprodan/AspNetCoreRateLimit/wiki
https://www.cnblogs.com/EminemJK/p/12720691.html (使用Redis缓存)

简介

在网站或API应用中,为了防止恶意攻击,通常希望屏蔽某一客户端短时间的内高频率请求。在ASP.NET Core中,AspNetCoreRateLimit为我们提供此功能。
AspNetCoreRateLimit是一个ASP.NET Core速率限制的解决方案,旨在控制客户端根据IP地址或客户端ID向Web API或MVC应用发出的请求的速率。AspNetCoreRateLimit包含一个IpRateLimitMiddleware和ClientRateLimitMiddleware,每个中间件可以根据不同的场景配置限制允许IP或客户端,自定义这些限制策略,也可以将限制策略应用在每​​个API URL或具体的HTTP Method上。

GitHub链接:https://github.com/stefanprodan/AspNetCoreRateLimit

配置文件

通过IP限制流量

{
  "IpRateLimiting": {
    //false则全局将应用限制,并且仅应用具有作为端点的规则* 。 true则限制将应用于每个端点,如{HTTP_Verb}{PATH}
    "EnableEndpointRateLimiting": true,
    //false:被拒绝的API调用不会添加到调用次数计数器上
    "StackBlockedRequests": false,   
    //表示获取用户端的真实IP
    "RealIpHeader": "X-Real-IP",
    "ClientIdHeader": "X-ClientId",
    "HttpStatusCode": 200,
    //自定义返回的内容
    "QuotaExceededResponse": {
      "Content": "{{"code":429,"msg":"访问过于频繁,请稍后重试","data":null}}",
      "ContentType": "application/json",
      "StatusCode": 200
    },
    "IpWhitelist": [ ],
    "EndpointWhitelist": [],
    "ClientWhitelist": [],
    "GeneralRules": [
      {
        "Endpoint": "*:/fw/*",
        "Period": "5s",
        "Limit": 3
      }
    ]
  }
}
  • EnableEndpointRateLimiting设置为true,意思是IP限制会应用于单个配置的Endpoint上。如果是false的话,只会限制所有 * 的规则,而不能达到针对单个Endpoint配置的目的。
  • HttpStatusCode设置为429,意思是触发限制之后给客户端返回的HTTP状态码。
  • GeneralRules里我只配置了一条,针对/fw这URL的限制。其中,开头的 : 表示任何HTTP VERB,如GET、POST,而结尾的 / 表示需要考虑/fw后面的参数,也就是我MVC Action参数里的route参数。
    针对不同参数,会有不同的计数。比如IP为127.0.0.1的用户在1分钟内请求了 /fw/abcd 10次,又请求了 /fw/qwer 25次,也请求了 /fw/996icu 32次。那么对于该用户,/fw/abcd 的机会还剩下20次,/fw/qwer 的机会还剩下5次,而 /fw/996icu 在第31次请求时会返回429。
  • StackBlockedRequests设置为true,表示被拒绝的请求会添加到计数器,比如配置了两个GeneralRules:(1秒2个请求)(10秒6个请求),你一秒访问了5次,其中三个请求被拒绝,这三个请求被加入了计数器,你10秒内只能请求6-3=3次了。如果您希望被拒绝的请求计入其他限制,则必须设置StackBlockedRequests为true。如果不希望被拒绝的请求加入计数器,就设置为false。
  • IpWhitelist是IP白名单,本地调试或者UAT环境,可以加入相应的IP,略过策略的限制;
  • EndpointWhitelist是端点白名单,如果全局配置了访问策略,设置端点白名单相当于IP白名单一样,略过策略的限制;
  • GeneralRules是具体的策略,根据不同需求配置不同端点即可, Period的单位可以是s, m, h, d,Limint是单位时间内的允许访问的次数;

通过ClientID限制流量

{
  "ClientRateLimiting": {
    "EnableEndpointRateLimiting": false,
    "EnableRegexRuleMatching": false,
    "StackBlockedRequests": false,
    "RealIpHeader": "X-Real-IP",
    "ClientIdHeader": "X-ClientId",
    "EndpointWhitelist": [ "get:/check/do" ],
    "ClientWhitelist": [ "other" ],
    "HttpStatusCode": 429,
    "GeneralRules": [
      {
        "Endpoint": "*",
        "Period": "1m",
        "Limit": 10
      }
    ]
  },
  "ClientRateLimitPolicies": {
    "ClientRules": [
      {
        "ClientId": "facebook",
        "Rules": [
          {
            "Endpoint": "*",
            "Period": "5s",
            "Limit": 2
          },
          {
            "Endpoint": "*",
            "Period": "10s",
            "Limit": 5
          }
        ]
      },
      {
        "ClientId": "other",
        "Rules": [
          {
            "Endpoint": "*",
            "Period": "5s",
            "Limit": 2
          }
        ]
      }
    ]
  }
}
  • ClientIdHeader用于设置ClientID的HeaderKey
  • ClientRateLimitPolicies 用于配置指定ClientID

代码

演示ClientID限制:

services.AddMemoryCache();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

var clientRateLimiting = configuration.GetSection("ClientRateLimiting");
            if (clientRateLimiting.Exists())
            {
                //公共配置
                services.Configure<ClientRateLimitOptions>(clientRateLimiting);
                //注入Policy存储器
                services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>();
                //注入计数器
                services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
                //计数器秘钥生成器
                services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
                var clientRateLimitPolicies = configuration.GetSection("ClientRateLimitPolicies");
                if (clientRateLimitPolicies.Exists())
                {
                    //客户端配置
                    services.Configure<ClientRateLimitPolicies>(clientRateLimitPolicies);
                }
            }

如果配置文件中有ClientRateLimitPolicies 元素,需要根据指定客户端做限制,就需要添加以下代码:

public static async Task Main(string[] args)
{
    IWebHost webHost = CreateWebHostBuilder(args).Build();
    using (var scope = webHost.Services.CreateScope())
    {
         // get the ClientPolicyStore instance
         var clientPolicyStore = scope.ServiceProvider.GetRequiredService<IClientPolicyStore>();
         // seed client data from appsettings
         await clientPolicyStore.SeedAsync();
    }
    await webHost.RunAsync();
}

以上代码的目的是在执行到中间件之前将ClientRateLimitPolicies配置信息写入缓存

原文地址:https://www.cnblogs.com/fanfan-90/p/14519358.html