Skip to main content

Rate Limiting | HTTP, SignalR | CSharp

  • Rate Limiting | HTTP, SignalR | CSharp

O que é Rate Limiting

Rate Limiting é uma técnica usada para controlar quantas ações um cliente pode realizar em um determinado intervalo de tempo.

Objetivos principais:

  • Evitar abuso de APIs
  • Prevenir ataques de DoS
  • Proteger recursos do servidor
  • Garantir qualidade de serviço (QoS)

Rate Limiting nativo do ASP.NET Core

A partir do .NET 7, o ASP.NET Core possui suporte nativo a Rate Limiting baseado em middleware.

Componentes principais:

  • AddRateLimiter
  • UseRateLimiter
  • EnableRateLimiting
  • Políticas (policies)

📌 Importante: Esse sistema funciona exclusivamente para requisições HTTP.


Tipos de Rate Limiting (HTTP)

Fixed Window

Permite N requisições por janela fixa de tempo.

📌 Exemplo: 5 requisições a cada 10 segundos.

options.AddFixedWindowLimiter("fixed", opt =>
{
opt.PermitLimit = 5;
opt.Window = TimeSpan.FromSeconds(10);
});

✔️ Simples

❌ Pode causar “picos” no início da janela


Sliding Window

A janela se move continuamente, evitando picos.

options.AddSlidingWindowLimiter("sliding", opt =>
{
opt.PermitLimit = 10;
opt.Window = TimeSpan.FromSeconds(30);
opt.SegmentsPerWindow = 3;
});

✔️ Mais preciso

❌ Um pouco mais custoso


Token Bucket

Tokens são adicionados ao longo do tempo. Cada requisição consome um token.

options.AddTokenBucketLimiter("token", opt =>
{
opt.TokenLimit = 10;
opt.ReplenishmentPeriod = TimeSpan.FromSeconds(5);
opt.TokensPerPeriod = 2;
opt.AutoReplenishment = true;
});

✔️ Excelente para APIs públicas

✔️ Suaviza tráfego

✔️ Muito usado em cloud


Concurrency Limiter

Limita requisições simultâneas.

options.AddConcurrencyLimiter("concurrent", opt =>
{
opt.PermitLimit = 3;
});

✔️ Protege recursos caros

❌ Não limita volume ao longo do tempo


Como aplicar EnableRateLimiting

Via Controller

[EnableRateLimiting("fixed")]
[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
{
}

Via Endpoint

app.MapControllers()
.RequireRateLimiting("token");

Pipeline

app.UseRateLimiter();

📌 O middleware precisa estar antes do mapeamento dos endpoints.


Por que EnableRateLimiting não funciona com SignalR

🔴 Motivo técnico

SignalR funciona com conexões persistentes:

  1. HTTP inicial (/negotiate)
  2. Upgrade para WebSocket
  3. Comunicação contínua sem novas requisições HTTP

➡️ O middleware não intercepta mensagens WebSocket.

📌 Resultado:

  • EnableRateLimiting só limita o negotiate
  • Mensagens do Hub não são afetadas

Tipos de Rate Limiting para SignalR

Rate Limit de Conexões (HTTP)

Limita quantas vezes um cliente pode conectar.

app.MapHub<ChatHub>("/chat")
.RequireRateLimiting("fixed");

✔️ Evita flood de conexões

❌ Não limita mensagens


Rate Limit por Método do Hub (manual)

Controle direto dentro do método.

public class ChatHub : Hub
{
private static readonly Dictionary<string, int> _calls = new();

public async Task SendMessage(string msg)
{
var id = Context.ConnectionId;

_calls.TryAdd(id, 0);
_calls[id]++;

if (_calls[id] > 10)
throw new HubException("Rate limit excedido");

await Clients.All.SendAsync("Receive", msg);
}
}

✔️ Simples

❌ Difícil de manter

❌ Duplicação de lógica


Hub Filters (Recomendado)

Funcionam como middleware do SignalR.

public class RateLimitHubFilter : IHubFilter
{
private static readonly Dictionary<string, int> _count = new();

public async ValueTask<object?> InvokeMethodAsync(
HubInvocationContext context,
Func<HubInvocationContext, ValueTask<object?>> next)
{
var id = context.Context.ConnectionId;

_count.TryAdd(id, 0);
_count[id]++;

if (_count[id] > 20)
throw new HubException("Muitas mensagens");

return await next(context);
}
}

Registro:

builder.Services.AddSignalR(opt =>
{
opt.AddFilter<RateLimitHubFilter>();
});

✔️ Centralizado

✔️ Reutilizável

✔️ Ideal para produção


Rate Limit Distribuído (Redis)

Usado em:

  • Load balancer
  • Azure SignalR
  • Múltiplas instâncias

📌 Exemplo conceitual:

  • Chave: signalr:{userId}
  • TTL: 1 segundo
  • Contador incremental

✔️ Escalável

✔️ Cloud-ready


Comparação Geral

CenárioMelhor abordagem
API RESTRateLimiter Middleware
Endpoint públicoToken Bucket
Recurso caroConcurrency
SignalR – conexõesEnableRateLimiting
SignalR – mensagensHub Filter
Ambiente distribuídoRedis

Boas Práticas

✔️ Nunca confie apenas em HTTP rate limit para SignalR

✔️ Prefira Hub Filters

✔️ Use Redis em ambientes distribuídos

✔️ Trate exceções com HubException

✔️ Separe limite de conexão e limite de mensagem


Conclusão

Rate Limiting HTTP e Rate Limiting em SignalR são problemas diferentes e exigem soluções diferentes.

  • Middleware → HTTP
  • Hub Filter → SignalR
  • Redis → Escala