수색…
비고
AspNetCoreRateLimit 는 클라이언트가 IP 주소 또는 클라이언트 ID를 기반으로 웹 API 또는 MVC 응용 프로그램에 요청할 수있는 비율을 제어하도록 설계된 오픈 소스 ASP.NET 코어 속도 제한 솔루션입니다.
클라이언트 IP를 기준으로 한 속도 제한
IpRateLimit 미들웨어를 사용하면 IP 또는 IP 범위에서 초당, 15 분과 같은 시간 간격으로 최대 통화 수를 허용하는 등 다양한 시나리오에 대해 여러 제한을 설정할 수 있습니다. 이러한 제한을 정의하여 API를 사용하거나 각 URL 경로 또는 HTTP 동사 및 경로의 한도를 지정할 수 있습니다.
설정
NuGet 설치 :
Install-Package AspNetCoreRateLimit
Startup.cs 코드 :
public void ConfigureServices(IServiceCollection services) { // needed to load configuration from appsettings.json services.AddOptions(); // needed to store rate limit counters and ip rules services.AddMemoryCache(); //load general configuration from appsettings.json services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); //load ip rules from appsettings.json services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies")); // inject counter and rules stores services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Add framework services. services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIpRateLimiting(); app.UseMvc(); }
loggerFactory를 제외한 다른 구성 요소보다 먼저 미들웨어를 등록해야합니다.
앱의 부하를 분산 시키려면 IDistributedCache
또는 SQLServer와 함께 IDistributedCache
를 사용해야 모든 kestrel 인스턴스가 동일한 속도 제한 저장소를 갖게됩니다. 메모리 저장소 대신 다음과 같이 분산 된 저장소를 주입해야합니다.
// inject counter and rules distributed cache stores services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
구성 및 일반 규칙 appsettings.json :
"IpRateLimiting": { "EnableEndpointRateLimiting": false, "StackBlockedRequests": false, "RealIpHeader": "X-Real-IP", "ClientIdHeader": "X-ClientId", "HttpStatusCode": 429, "IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ], "EndpointWhitelist": [ "get:/api/license", "*:/api/status" ], "ClientWhitelist": [ "dev-id-1", "dev-id-2" ], "GeneralRules": [ { "Endpoint": "*", "Period": "1s", "Limit": 2 }, { "Endpoint": "*", "Period": "15m", "Limit": 100 }, { "Endpoint": "*", "Period": "12h", "Limit": 1000 }, { "Endpoint": "*", "Period": "7d", "Limit": 10000 } ] }
EnableEndpointRateLimiting
을 false
로 설정하면 제한이 전역 적으로 적용되고 끝점 *
이있는 규칙 만 적용됩니다. 예를 들어 초당 5 개의 통화 제한을 설정하면 모든 종단점에 대한 모든 HTTP 호출이 해당 제한에 포함됩니다.
EnableEndpointRateLimiting
이 true
로 설정된 경우 {HTTP_Verb}{PATH}
와 같이 각 끝점에 대한 제한이 적용됩니다. 예를 들어, *:/api/values
대해 초당 5 개의 호출 수를 설정하면 클라이언트는 초당 GET /api/values
5 번이나 PUT /api/values
5 배까지 호출 할 수 있습니다.
StackBlockedRequests
를 false
로 설정하면 거부 된 통화가 스로틀 카운터에 추가되지 않습니다. 클라이언트가 초당 3 건의 요청을 처리하고 초당 한 건의 제한을 설정 한 경우 분당 또는 일 카운터와 같은 다른 제한은 차단되지 않은 첫 번째 호출 만 기록합니다. 거부 된 요청이 다른 제한값에 포함되도록하려면 StackBlockedRequests
를 true
로 설정해야 true
.
RealIpHeader
는 Kestrel 서버가 역방향 프록시 뒤에있을 때 클라이언트 IP를 추출하는 데 사용됩니다. 프록시가 다른 헤더를 사용하면 X-Real-IP
가이 옵션을 사용하여이를 설정합니다.
ClientIdHeader
는 흰색 목록에 대한 클라이언트 ID를 추출하는 데 사용됩니다. 클라이언트 ID가이 헤더에 있고 ClientWhitelist에 지정된 값과 일치하면 속도 제한이 적용되지 않습니다.
특정 IP에 대한 일반 규칙 덮어 쓰기 appsettings.json :
"IpRateLimitPolicies": { "IpRules": [ { "Ip": "84.247.85.224", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 10 }, { "Endpoint": "*", "Period": "15m", "Limit": 200 } ] }, { "Ip": "192.168.3.22/25", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 5 }, { "Endpoint": "*", "Period": "15m", "Limit": 150 }, { "Endpoint": "*", "Period": "12h", "Limit": 500 } ] } ] }
IP 필드는 IP v4 및 v6 값과 범위 "192.168.0.0/24", "fe80 :: / 10"또는 "192.168.0.0-192.168.0.255"를 지원합니다.
비율 제한 규칙 정의
규칙은 끝점, 마침표 및 한도로 구성됩니다.
종점 형식은 {HTTP_Verb}:{PATH}
이며, 별표 기호를 사용하여 모든 HTTP 동사를 타겟팅 할 수 있습니다.
기간 형식은 {INT}{PERIOD_TYPE}
입니다. 다음 기간 유형 중 하나를 사용할 수 있습니다 : s, m, h, d
.
제한 형식은 {LONG}
입니다.
예 :
속도는 모든 엔드 포인트를 초당 2 통화로 제한합니다.
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
동일한 IP에서 동일한 초에 api / value로 3 GET 호출을하면 마지막 호출이 차단됩니다. 하지만 PUT api / values도 같은 초에 호출하면 다른 끝점이기 때문에 요청이 완료됩니다. 끝점 속도 제한이 활성화되면 각 통화는 {HTTP_Verb}{PATH}
에 따라 요금이 제한됩니다.
모든 HTTP 동사와 /api/values
을 포함하는 속도 제한 호출은 15 분당 5 개의 호출로 제한됩니다.
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
속도 제한 /api/values
에 대한 GET 호출을 시간당 5 개의 호출로 지정합니다.
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
동일한 IP에서 한 시간 후에 API / 값으로 6 번의 GET 호출을하면 마지막 호출이 차단됩니다. 하지만 같은 시간에 GET API / 값 / 1을 호출하면 다른 끝점이기 때문에 요청이 완료됩니다.
행동
클라이언트가 HTTP 호출을하면 IpRateLimitMiddleware는 다음을 수행합니다.
- 요청 개체에서 IP, 클라이언트 ID, HTTP 동사 및 URL을 추출합니다. 추출 논리를 직접 구현하려는 경우
IpRateLimitMiddleware.SetIdentity
재정의 할 수 있습니다. - 흰색 목록에서 IP, 클라이언트 ID 및 URL을 검색하고 일치하는 경우 아무런 조치도 취하지 않습니다.
- IP 규칙에서 일치하는 항목을 검색하면 적용되는 모든 규칙이 기간별로 그룹화됩니다. 각 규칙에 대해 가장 제한적인 규칙이 사용됩니다
- 일반 규칙에서 일치하는 항목을 검색 할 때 일치하는 일반 규칙에 정의 된 기간이 IP 규칙에없는 경우이 일반 규칙도 사용됩니다
- 각 일치 규칙에 대해 속도 제한 카운터가 증가되고, 카운터 값이 규칙 제한보다 크면 요청이 차단됩니다
요청이 차단되면 클라이언트는 다음과 같은 텍스트 응답을받습니다.
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
이러한 옵션을 변경하여 응답을 사용자 정의 할 수 있습니다. HttpStatusCode
및 QuotaExceededMessage
. 사용자가 직접 응답을 구현하려는 경우 IpRateLimitMiddleware.ReturnQuotaExceededResponse
대체 할 수 있습니다. Retry-After
헤더 값은 초 단위로 표시됩니다.
요청이 속도 제한을받지 못하면 일치 규칙에 정의 된 가장 긴 기간이 X-Rate-Limit 헤더를 작성하는 데 사용되며 다음 헤더가 응답에 삽입됩니다.
X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)
X-Rate-Limit-Remaining: number of request remaining
X-Rate-Limit-Reset: UTC date time when the limits resets
기본적으로 차단 된 요청은 Microsoft.Extensions.Logging.ILogger
사용하여 기록됩니다. 자체 로깅을 구현하려면 IpRateLimitMiddleware.LogBlockedRequest
재정의 할 수 있습니다. 기본 로거는 요청이 속도 제한에 도달하면 다음 정보를 방출합니다.
info: AspNetCoreRateLimit.IpRateLimitMiddleware[0]
Request get:/api/values from IP 84.247.85.224 has been blocked, quota 2/1m exceeded by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.
런타임시 속도 제한 업데이트
응용 프로그램 시작시 appsettings.json
정의 된 IP 속도 제한 규칙은 사용중인 캐시 공급자 유형에 따라 MemoryCacheClientPolicyStore
또는 DistributedCacheIpPolicyStore
에 의해 캐시에로드됩니다. 컨트롤러 내부의 IP 정책 저장소에 액세스하여 다음과 같이 IP 규칙을 수정할 수 있습니다.
public class IpRateLimitController : Controller { private readonly IpRateLimitOptions _options; private readonly IIpPolicyStore _ipPolicyStore; public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore ipPolicyStore) { _options = optionsAccessor.Value; _ipPolicyStore = ipPolicyStore; } [HttpGet] public IpRateLimitPolicies Get() { return _ipPolicyStore.Get(_options.IpPolicyPrefix); } [HttpPost] public void Post() { var pol = _ipPolicyStore.Get(_options.IpPolicyPrefix); pol.IpRules.Add(new IpRateLimitPolicy { Ip = "8.8.4.4", Rules = new List<RateLimitRule>(new RateLimitRule[] { new RateLimitRule { Endpoint = "*:/api/testupdate", Limit = 100, Period = "1d" } }) }); _ipPolicyStore.Set(_options.IpPolicyPrefix, pol); } }
이렇게하면 데이터베이스에 IP 속도 제한을 저장하고 각 앱이 시작된 후 캐시에 푸시 할 수 있습니다.
클라이언트 ID를 기반으로 한 속도 제한
ClientRateLimit 미들웨어를 사용하면 클라이언트가 초당, 15 분과 같은 시간 간격으로 최대 횟수의 호출을 할 수 있도록하는 것과 같은 여러 시나리오에 대해 여러 제한을 설정할 수 있습니다. 이러한 제한을 정의하여 API 또는 각 URL 경로 또는 HTTP 동사와 경로에 한도를 적용 할 수 있습니다.
설정
NuGet 설치 :
Install-Package AspNetCoreRateLimit
Startup.cs 코드 :
public void ConfigureServices(IServiceCollection services) { // needed to load configuration from appsettings.json services.AddOptions(); // needed to store rate limit counters and ip rules services.AddMemoryCache(); //load general configuration from appsettings.json services.Configure<ClientRateLimitOptions>(Configuration.GetSection("ClientRateLimiting")); //load client rules from appsettings.json services.Configure<ClientRateLimitPolicies>(Configuration.GetSection("ClientRateLimitPolicies")); // inject counter and rules stores services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Add framework services. services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseClientRateLimiting(); app.UseMvc(); }
loggerFactory를 제외한 다른 구성 요소보다 먼저 미들웨어를 등록해야합니다.
앱의 부하를 분산 시키려면 IDistributedCache
또는 SQLServer와 함께 IDistributedCache
를 사용해야 모든 kestrel 인스턴스가 동일한 속도 제한 저장소를 갖게됩니다. 메모리 저장소 대신 다음과 같이 분산 된 저장소를 주입해야합니다.
// inject counter and rules distributed cache stores services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
구성 및 일반 규칙 appsettings.json :
"ClientRateLimiting": { "EnableEndpointRateLimiting": false, "StackBlockedRequests": false, "ClientIdHeader": "X-ClientId", "HttpStatusCode": 429, "EndpointWhitelist": [ "get:/api/license", "*:/api/status" ], "ClientWhitelist": [ "dev-id-1", "dev-id-2" ], "GeneralRules": [ { "Endpoint": "*", "Period": "1s", "Limit": 2 }, { "Endpoint": "*", "Period": "15m", "Limit": 100 }, { "Endpoint": "*", "Period": "12h", "Limit": 1000 }, { "Endpoint": "*", "Period": "7d", "Limit": 10000 } ] }
EnableEndpointRateLimiting
을 false
로 설정하면 제한이 전역 적으로 적용되고 끝점 *
이있는 규칙 만 적용됩니다. 예를 들어 초당 5 개의 통화 제한을 설정하면 모든 종단점에 대한 모든 HTTP 호출이 해당 제한에 포함됩니다.
EnableEndpointRateLimiting
이 true
로 설정된 경우 {HTTP_Verb}{PATH}
와 같이 각 끝점에 대한 제한이 적용됩니다. 예를 들어, *:/api/values
대해 초당 5 개의 호출 수를 설정하면 클라이언트는 초당 GET /api/values
5 번이나 PUT /api/values
5 배까지 호출 할 수 있습니다.
StackBlockedRequests
를 false
로 설정하면 거부 된 통화가 스로틀 카운터에 추가되지 않습니다. 클라이언트가 초당 3 건의 요청을 처리하고 초당 한 건의 제한을 설정 한 경우 분당 또는 일 카운터와 같은 다른 제한은 차단되지 않은 첫 번째 호출 만 기록합니다. 거부 된 요청이 다른 제한값에 포함되도록하려면 StackBlockedRequests
를 true
로 설정해야 true
.
ClientIdHeader
를 사용하여 클라이언트 ID를 추출합니다. 클라이언트 ID가이 헤더에 있고 ClientWhitelist에 지정된 값과 일치하면 속도 제한이 적용되지 않습니다.
특정 클라이언트에 대한 일반 규칙 재정의 appsettings.json :
"ClientRateLimitPolicies": { "ClientRules": [ { "ClientId": "client-id-1", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 10 }, { "Endpoint": "*", "Period": "15m", "Limit": 200 } ] }, { "Client": "client-id-2", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 5 }, { "Endpoint": "*", "Period": "15m", "Limit": 150 }, { "Endpoint": "*", "Period": "12h", "Limit": 500 } ] } ] }
비율 제한 규칙 정의
규칙은 끝점, 마침표 및 한도로 구성됩니다.
종점 형식은 {HTTP_Verb}:{PATH}
이며, 별표 기호를 사용하여 모든 HTTP 동사를 타겟팅 할 수 있습니다.
기간 형식은 {INT}{PERIOD_TYPE}
입니다. 다음 기간 유형 중 하나를 사용할 수 있습니다 : s, m, h, d
.
제한 형식은 {LONG}
입니다.
예 :
속도는 모든 엔드 포인트를 초당 2 통화로 제한합니다.
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
같은 초에 클라이언트가 API / 값에 3 GET 호출을하면 마지막 호출이 차단됩니다. 하지만 동일한 초에 PUT api / values를 호출하면 다른 끝점이기 때문에 요청이 완료됩니다. 끝점 속도 제한이 활성화되면 각 통화는 {HTTP_Verb}{PATH}
에 따라 요금이 제한됩니다.
모든 HTTP 동사와 /api/values
을 포함하는 속도 제한 호출은 15 분당 5 개의 호출로 제한됩니다.
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
속도 제한 /api/values
에 대한 GET 호출을 시간당 5 개의 호출로 지정합니다.
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
한 시간 내에 클라이언트가 API / 값을 6 번 호출하면 마지막 호출이 차단됩니다. 그러나 같은 시간에 GET api / values / 1이라도 호출하면 다른 끝점이기 때문에 요청이 완료됩니다.
행동
클라이언트가 HTTP 호출을하면 ClientRateLimitMiddleware는 다음을 수행합니다.
- 요청 개체에서 클라이언트 ID, HTTP 동사 및 URL을 추출합니다. 추출 논리를 직접 구현하려는 경우
ClientRateLimitMiddleware.SetIdentity
재정의 할 수 있습니다. - 흰색 목록에서 클라이언트 ID 및 URL을 검색하고 일치하는 경우 아무런 조치도 취하지 않습니다.
- 클라이언트 규칙에서 일치하는 항목을 검색하면 적용되는 모든 규칙이 기간별로 그룹화됩니다. 가장 제한적인 규칙이 사용되는 기간마다
- 일반 규칙에서 일치하는 항목을 검색합니다. 일치하는 일반 규칙에 정의 된 기간이 클라이언트 규칙에없는 경우이 일반 규칙도 사용됩니다
- 각 일치 규칙에 대해 속도 제한 카운터가 증가되고, 카운터 값이 규칙 제한보다 크면 요청이 차단됩니다
요청이 차단되면 클라이언트는 다음과 같은 텍스트 응답을받습니다.
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
이 옵션을 변경하여 응답을 사용자 정의 할 수 있습니다. HttpStatusCode
및 QuotaExceededMessage
. 사용자 자신의 응답을 구현하려는 경우 ClientRateLimitMiddleware.ReturnQuotaExceededResponse
대체 할 수 있습니다. Retry-After
헤더 값은 초 단위로 표시됩니다.
요청이 속도 제한을받지 못하면 일치 규칙에 정의 된 가장 긴 기간이 X-Rate-Limit 헤더를 작성하는 데 사용되며 다음 헤더가 응답에 삽입됩니다.
X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)
X-Rate-Limit-Remaining: number of request remaining
X-Rate-Limit-Reset: UTC date time when the limits resets
기본적으로 차단 된 요청은 Microsoft.Extensions.Logging.ILogger
사용하여 기록됩니다. 자체 로깅을 구현하려면 ClientRateLimitMiddleware.LogBlockedRequest
재정의 할 수 있습니다. 기본 로거는 요청이 속도 제한에 도달하면 다음 정보를 방출합니다.
info: AspNetCoreRateLimit.ClientRateLimitMiddleware[0]
Request get:/api/values from ClientId client-id-1 has been blocked, quota 2/1m exceeded by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.
런타임시 속도 제한 업데이트
응용 프로그램 시작시 appsettings.json
정의 된 클라이언트 속도 제한 규칙은 사용중인 캐시 공급자 유형에 따라 MemoryCacheClientPolicyStore
또는 DistributedCacheClientPolicyStore
에 의해 캐시에로드됩니다. 컨트롤러 내부의 클라이언트 정책 저장소에 액세스하여 다음과 같이 규칙을 수정할 수 있습니다.
public class ClientRateLimitController : Controller { private readonly ClientRateLimitOptions _options; private readonly IClientPolicyStore _clientPolicyStore; public ClientRateLimitController(IOptions<ClientRateLimitOptions> optionsAccessor, IClientPolicyStore clientPolicyStore) { _options = optionsAccessor.Value; _clientPolicyStore = clientPolicyStore; } [HttpGet] public ClientRateLimitPolicy Get() { return _clientPolicyStore.Get($"{_options.ClientPolicyPrefix}_cl-key-1"); } [HttpPost] public void Post() { var id = $"{_options.ClientPolicyPrefix}_cl-key-1"; var clPolicy = _clientPolicyStore.Get(id); clPolicy.Rules.Add(new RateLimitRule { Endpoint = "*/api/testpolicyupdate", Period = "1h", Limit = 100 }); _clientPolicyStore.Set(id, clPolicy); } }
이렇게하면 데이터베이스에 클라이언트 속도 제한을 저장하고 각 앱이 시작된 후 캐시에 푸시 할 수 있습니다.