Skip to content
This page has been auto-translated and may contain errors.View in English

Fundamentos de rate limiting

Um cliente pode fazer mil requisições por segundo. Nada no HTTP os impede, e seu servidor vai tentar responder a todas elas.

Rate limiting controla quanto tráfego um serviço aceita. É a diferença entre um endpoint que sobrevive a uma tarde ruim e um que cai porque um único script ficou empolgado demais.

Três problemas que ele resolve

Uso justo. Um cliente monopolizando recursos significa que todos os outros esperam. Um limite impede que um único chamador consuma o que toda a base de usuários precisa, então o tráfego legítimo continua sendo atendido enquanto o loop descontrolado de alguém é recusado.

Segurança. Um endpoint de login sem limite é um convite para tentar adivinhar senhas, aos milhares de uma vez. Limites tornam a força bruta lenta demais para ser útil, e amenizam os ataques mais simples de negação de serviço.

Recursos. A sobrecarga deixa um serviço lento antes de deixá-lo indisponível, e é na lentidão que os usuários desistem. Limitar a taxa de processamento mantém os tempos de resposta previsíveis para todo mundo que ainda está dentro do limite.

Limites não são uma defesa contra DDoS por si só

Um ataque distribuído de negação de serviço chega a partir de milhares de máquinas diferentes, cada uma parecendo um cliente comum. Limites por endereço praticamente não afetam isso.

Responder a isso exige algo antes na cadeia: filtragem geográfica, análise comportamental, ou um provedor posicionado à sua frente. Rate limiting é uma camada, não a solução completa.

JunoTrês problemas que ele resolve Os três se sobrepõem, e é por isso que um único controle cobre todos eles. Uso justo, segurança e proteção de recursos são o mesmo mecanismo visto de ângulos diferentes.

Limitar a frequência com que alguém pode fazer pedidos é o que torna um aplicativo difícil de abusar e agradável para todo mundo ao mesmo tempo.

JunoTrês problemas que ele resolve Os limites que vale a pena definir primeiro geralmente não são os globais. Um endpoint de login, uma redefinição de senha, um cadastro, uma busca que sobrecarrega o banco de dados: esses merecem limites próprios e bem apertados, muito antes de um teto geral sobre tudo.

A pergunta útil para cada endpoint é o que um usuário legítimo poderia plausivelmente fazer em um minuto, e então deixar uma folga acima disso.

JunoTrês problemas que ele resolve Rate limiting no login tem uma sutileza que vale a pena conhecer: limitar por endereço pune um escritório inteiro atrás de um único endereço, enquanto limitar por nome de usuário permite que um atacante bloqueie qualquer conta que escolher, falhando o login dela de propósito.

O formato que funciona é limitar os dois, com orçamentos diferentes, e nunca bloquear uma conta só por causa de falhas. Desacelerar as respostas funciona melhor aqui do que bloquear, porque custa tempo ao atacante sem entregar a ele uma negação de serviço contra os seus próprios usuários.

Recusar versus desacelerar

Dois controles relacionados que são usados como sinônimos e se comportam de forma diferente.

Rate limitingThrottling
O que fazRecusa requisições acima de um tetoDesacelera requisições conforme o limite se aproxima
O que o cliente vêUm erro, geralmente 429 Too Many RequestsUma resposta, mais demorada que o normal
Melhor paraTetos rígidos que você quer imporSuavizar picos sem quebrar os clientes

Rate limiting recusa acima de um teto. Throttling desacelera.

Os dois têm seu lugar, e se combinam: desacelere conforme o tráfego cresce, recuse totalmente acima de um teto rígido. Throttling cobre a segunda metade em detalhes.

JunoRecusar versus desacelerar Uma forma útil de guardar a diferença: recusar diz não, e desacelerar diz não tão rápido.

Um quebra a requisição do cliente. O outro faz o cliente esperar. Qual é mais gentil depende inteiramente de quem está chamando e por quê.

JunoRecusar versus desacelerar Throttling é mais amigável para um cliente bem-comportado que pediu demais por um instante, porque a requisição dele ainda é bem-sucedida. É pior contra abuso, já que manter requisições em espera custa a você conexões e memória.

Então o arranjo comum é desacelerar o meio e recusar o topo: suave para clientes que se desviam um pouco, firme para qualquer coisa muito acima.

JunoRecusar versus desacelerar Um 429 só é útil se o cliente puder agir a partir dele, o que significa Retry-After, além dos cabeçalhos RateLimit informando o limite, o que resta e quando ele reinicia. Sem isso, a única estratégia do cliente é tentar de novo imediatamente, exatamente o que você estava tentando evitar.

O modo de falha contra o qual é preciso se projetar é a tempestade de retentativas: todo mundo recusado no mesmo instante, todo mundo tentando de novo no mesmo instante. Jitter no backoff do cliente e reinícios escalonados são o que desfazem isso, e nenhum dos dois acontece por acaso.

Contra o que um limite conta

Um limite precisa de algo para contar por unidade. Quatro candidatos, cada um com trocas diferentes:

  • Endereço IP. Disponível em toda requisição, inclusive nas anônimas, e compartilhado por todo mundo atrás de uma rede corporativa ou de uma operadora de celular.
  • Id do usuário autenticado. Preciso e justo, e só existe depois do login.
  • Chave de API. Ideal para clientes automatizados, já que uma chave identifica um chamador com exatidão.
  • Uma claim dentro de um JWT. Útil quando a identidade já viaja dentro do token.

Identificar clientes trata de como escolher entre eles. Resumindo: o tráfego anônimo deixa você só com o endereço, e todo o resto é melhor quando está disponível.

Limites também precisam de uma janela de tempo. Por segundo, por minuto, por hora, e essa escolha molda o comportamento tanto quanto o número em si.

JunoContra o que um limite conta "Cem requisições" não significa nada sem mais duas informações: cem por quê, e cem de quem.

Todo rate limit é essas três decisões juntas, e mudar qualquer uma delas muda o que o limite realmente faz.

JunoContra o que um limite conta O tamanho da janela importa mais do que as pessoas esperam. Cem por hora e duas por minuto dão a mesma média, mas não se comportam nada parecido: o primeiro permite cem requisições em um segundo e depois silêncio, o segundo nunca permite pico nenhum.

Janelas curtas suavizam o tráfego. Janelas longas toleram picos. Escolha pensando no tráfego que você realmente quer permitir.

JunoContra o que um limite conta Seja lá o que você usa para contar, isso se torna algo que um atacante pode trocar. Endereços são baratos em pools de proxy residencial; contas gratuitas são baratas a menos que o próprio cadastro seja protegido; chaves de API são a exceção, já que emitir uma é um ato deliberado.

O que revela o limite honesto desse controle: ele torna o abuso caro em vez de impossível, e o preço é definido por quão difícil é conseguir seu identificador mais barato.

Vale decidir cedo também onde fica o próprio estado do limitador. Contadores em processo são simples e ficam errados no momento em que você roda duas instâncias, porque cada uma mantém sua própria contagem e o limite efetivo dobra.

Coloque em prática

Uma API tem um único limite: 1.000 requisições por hora por endereço IP. Descubra o que ela não consegue evitar.

  1. Um usuário em uma rede universitária não consegue usar o aplicativo durante o período letivo. Por quê?
  2. Um atacante quer 10.000 requisições por hora. Quanto isso custa a ele?
  3. Um script envia todas as 1.000 requisições nos primeiros dois segundos de cada hora. Isso está dentro do limite?
Compare suas respostas

1. O limite conta a coisa errada. Todo mundo naquela rede compartilha um único endereço de saída, então milhares de pessoas estão dividindo um orçamento de mil. A correção é contar por usuário autenticado onde existe um usuário, e manter o limite por endereço só para o tráfego anônimo.

2. Dez endereços. Pools de proxy residencial vendem esses aos milhares por muito pouco. Limites por endereço fazem o abuso custar algo; não o tornam difícil. Essa é a mesma razão pela qual limitar por IP praticamente não afeta um ataque distribuído.

3. Totalmente dentro do limite. Nada diz como as mil requisições devem ser distribuídas, então todas elas podem chegar de uma vez, e o endpoint enfrenta um pico contra o qual nunca esteve protegido. É isso que o tamanho da janela controla, e escolher uma janela de uma hora permite um pico que uma janela de um minuto jamais permitiria.

Três perguntas, três fraquezas diferentes, e só a terceira é sobre o algoritmo. As duas primeiras são sobre o que você conta e quão barato isso pode ser substituído.

Para onde isso vai a seguir

Um limite precisa de três decisões: quanto, em qual janela, contado contra quem. O algoritmo é como você acompanha isso.

Contadores de janela fixa é o mais simples desses algoritmos, e o pico que ele deixa passar é exatamente o que todo algoritmo seguinte existe para corrigir.