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配置信息写入缓存