參考:
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配置信息寫入緩存