수색…


비고

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
      }
    ]
  }

EnableEndpointRateLimitingfalse 로 설정하면 제한이 전역 적으로 적용되고 끝점 * 이있는 규칙 만 적용됩니다. 예를 들어 초당 5 개의 통화 제한을 설정하면 모든 종단점에 대한 모든 HTTP 호출이 해당 제한에 포함됩니다.

EnableEndpointRateLimitingtrue 로 설정된 경우 {HTTP_Verb}{PATH} 와 같이 각 끝점에 대한 제한이 적용됩니다. 예를 들어, *:/api/values 대해 초당 5 개의 호출 수를 설정하면 클라이언트는 초당 GET /api/values 5 번이나 PUT /api/values 5 배까지 호출 할 수 있습니다.

StackBlockedRequestsfalse 로 설정하면 거부 된 통화가 스로틀 카운터에 추가되지 않습니다. 클라이언트가 초당 3 건의 요청을 처리하고 초당 한 건의 제한을 설정 한 경우 분당 또는 일 카운터와 같은 다른 제한은 차단되지 않은 첫 번째 호출 만 기록합니다. 거부 된 요청이 다른 제한값에 포함되도록하려면 StackBlockedRequeststrue 로 설정해야 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.

이러한 옵션을 변경하여 응답을 사용자 정의 할 수 있습니다. HttpStatusCodeQuotaExceededMessage . 사용자가 직접 응답을 구현하려는 경우 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
      }
    ]
  }

EnableEndpointRateLimitingfalse 로 설정하면 제한이 전역 적으로 적용되고 끝점 * 이있는 규칙 만 적용됩니다. 예를 들어 초당 5 개의 통화 제한을 설정하면 모든 종단점에 대한 모든 HTTP 호출이 해당 제한에 포함됩니다.

EnableEndpointRateLimitingtrue 로 설정된 경우 {HTTP_Verb}{PATH} 와 같이 각 끝점에 대한 제한이 적용됩니다. 예를 들어, *:/api/values 대해 초당 5 개의 호출 수를 설정하면 클라이언트는 초당 GET /api/values 5 번이나 PUT /api/values 5 배까지 호출 할 수 있습니다.

StackBlockedRequestsfalse 로 설정하면 거부 된 통화가 스로틀 카운터에 추가되지 않습니다. 클라이언트가 초당 3 건의 요청을 처리하고 초당 한 건의 제한을 설정 한 경우 분당 또는 일 카운터와 같은 다른 제한은 차단되지 않은 첫 번째 호출 만 기록합니다. 거부 된 요청이 다른 제한값에 포함되도록하려면 StackBlockedRequeststrue 로 설정해야 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.

이 옵션을 변경하여 응답을 사용자 정의 할 수 있습니다. HttpStatusCodeQuotaExceededMessage . 사용자 자신의 응답을 구현하려는 경우 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);
    }
}

이렇게하면 데이터베이스에 클라이언트 속도 제한을 저장하고 각 앱이 시작된 후 캐시에 푸시 할 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow