수색…
비고
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);
}
}
이렇게하면 데이터베이스에 클라이언트 속도 제한을 저장하고 각 앱이 시작된 후 캐시에 푸시 할 수 있습니다.