Rate Limiting em APIs com ASP.NET Core 7.0

Neste artigo vou abordar uma nova funcionalidade nativa no ASP.NET Core, na versão 7.0: o middleware de rate limiting!

Vai ser apresentado o que é o rate limiting e seus benefícios, e como configurar e utilizar este recurso em sua API ASP.NET Core.

O que é Rate Limiting

Vamos começar pelo conceito de Rate Limiting. Ele é uma estratégia para restringir o tráfego de rede recebido por sua aplicação, limitando a quantidade de requisições realizadas em um certo período de tempo. Geralmente isso é feito através do rastreamento de endereços IP que realizam as requisições, junto ao período de tempo dessas. Em caso de quantidade acima da permitida de requisições no intervalo de tempo definido, novas requisições não serão completadas por um período de tempo.

É uma estratégia essencial contra algumas atividades maliciosas, como ataques de bots. Estes tipos de ataques, como ataques de força bruta e DDoS, afetam negativamente aplicações, potencialmente inclusive derrubando uma aplicação ou aumentando muito os custos de nuvem. É comum de ser utilizada em APIs Gateways, como por exemplo Kong, Azure API Management e Ocelot.

O Rate Limiting também contribui para um maior controle de carga dos serviços web publicados, sendo muito comum também em APIs abertas, como consultas de endereço.

Já imaginou um recurso de nuvem com dimensionamento automático (Auto Scale_) configurado, recebendo um ataque em massa desse tipo? Os recursos consumidos (infraestrutura e dinheiro) acabarão escalando juntos, causando dore$ de cabeça!

Adicionando em sua API com ASP.NET Core

O primeiro passo é configurá-lo na classe Program. Utilizamos o método AddRateLimiter para o objeto de tipo IServiceCollection (builder.Services). Serão definidas algumas propriedades do Rate Limiting através do objeto de classe RateLimiterOptionsExtensions , como:

  • PermitLimit: define o número máximo de requisições para uma janela (definida na propriedade Window) específica. Tipo int;
  • Window: define o tempo de janela para requisições. Tipo TimeSpan;
  • QueueProcessingOrder: define a ordem de processamento. Tipo QueueProcessingOrder;
  • QueueLimit: Define a quantidade máxima permitida de requisições acumuladas. Tipo int.;

Existem alguns tipos de Rate Limiting que podem ser implementados, mas vou focar em 2 deles: FixedWindowLimiter e SlidingWindowLimiter.

  • Fixed Window Limiter: janela fixa de tempo e quantidade de requisições, reiniciando o limite de requisições quando passar desse período. Por exemplo, se eu fizer 3 requisições em 10 segundos, e tiver um limite fixo de 2 a cada 10 segundos, seria possível realizar 3 requisições durante os 10 segundos se a janela fosse reiniciada no meio tempo;
  • Sliding Window Limiter: janela variável de tempo e quantidade requisições, movendo o segmento a cada intervalo de tempo de segmento. Logo, não existe um período de tempo onde se “reinicia” a contagem, sempre se está avaliando a quantidade de requisições no intervalo de tempo de segmento definido. Usando o mesmo exemplo anterior, se eu realizar 3 chamadas em 10 segundos e o limite for 2, não será permitida a terceira, pois a janela é variável (últimos 10 segundos), ao invés de ter uma janela fixa como o Fixed Window Limiter.

Abaixo você encontra o código de configuração para ambos tipos na classe Program, para restringir em 5 requisições em um período de 10 segundos. Lembrando que essa é apenas uma parte do arquivo, focada apenas na configuração (com exceção da declaração da variável app, que já é feita por padrão).

builder.Services.AddRateLimiter(_ => _
    .AddFixedWindowLimiter("fixed", options =>
    {
        options.PermitLimit = 5;
        options.Window = TimeSpan.FromSeconds(10);
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = 2;
    })
    .AddSlidingWindowLimiter("sliding", options =>
    {
        options.PermitLimit = 5;
        options.Window = TimeSpan.FromSeconds(10);
        options.SegmentsPerWindow = 5;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = 2;
    }));

var app = builder.Build();

app.UseRateLimiter();

Pontos de atenção:

  • O primeiro parêmetro dos métodos AddFixedWindowLimiter e AddSlidingWindowLimiter é o policyName, que é o identificador da política de Rate Limiting sendo especificado, e que precisará ser passado no momento de atribuir ao Controller ou Action, como será feito posteriormente;
  • Após configurar os Rate Limiters, é necessário chamar app.UseRateLimiter() parade fato utilizá-los;

Como exemplo vou utilizar algo que já percebi o Rate Limiting: retorno de endereço baseado no CEP.

No Controller de exemplo CepsController vamos definir o uso do Fixed Window Limiter através da anotação EnableRateLimiting, que recebe como parâmetro o nome do policy de Rate Limiting definido na contribuição.


using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;

namespace RateLimitingDemo.Controllers
{
    [Route("api/ceps")]
    [ApiController]
    [EnableRateLimiting("fixed")]
    public class CepsController : ControllerBase
    {
        [HttpGet("{cep}")]
        public IActionResult GetFullAddressByCep(string cep)
        {
            return Ok();
        }

        [HttpGet("ping")]
        [EnableRateLimiting("sliding")]
        public IActionResult Ping()
        {
            return Ok("pong");
        }
    }
}

Veja como é possível atribuir a nível de Controller ou a Action apenas!

Ao executar a aplicação, e tentar executar mais de 5 requisições no período de 10 segundos (cuja avaliação depende do tipo de Rate Limiter utilizado), as requisições seguintes ficarão aguardando o tempo de janela ser reiniciado, para então receberem suas respostas. Prático, né?


Quer alavancar sua carreira como Desenvolvedor(a) .NET?

Além de Desenvolvedor .NET Sênior, eu sou instrutor de mais de 700 alunos e também tenho dezenas de mentorados.

Conheça o Método .NET Direto ao Ponto, minha plataforma com mais de 800 videoaulas, com cursos cobrindo temas relacionados a linguagem C# e Programação Orientada a Objetos, APIs REST com ASP NET Core, Microsserviços com ASP NET Core, HTML, CSS e JavaScript, Desenvolvimento Front-end com Angular, Desenvolvimento Front-end com React, JavaScript Intermediário, TypeScript, Formação Arquitetura de Software, Microsoft Azure, Agile, SQL, e muito mais.

Inclui comunidade de centenas de alunos, suporte por ela, plataforma e e-mail, atualizações regulares e muito mais.

Clique aqui para ter mais informações e garantir sua vaga


Conclusão

Vimos neste artigo o que é Rate Limiting, seus principais conceitos e benefícios, e como configurar e utilizar essa estratégia em sua API que utiliza a versão 7 do ASP.NET Core.

Não podemos nos dar o luxo de não se preocupar com atividades maliciosas, como bots ou abuso de nossas APIs. Definir um Rate Limiter nos protege de algumas dessas atividades, ajudando a proteger tanto nossa infraestrutura quanto as finanças.