Rate Limiting e Prevenção de Abuso em um App Construído com IA
Resposta rápida
Rate limiting não é uma configuração única que você liga e esquece — são algumas verificações pequenas e em camadas: um limite por IP na borda, um limite por usuário em rotas caras, e um limite separado e mais apertado em qualquer coisa que chame um LLM ou envie e-mail. Pule isso e o primeiro bot que encontrar seu formulário de cadastro vai criar dez mil contas antes do almoço, com o maior prazer.
Por que isso fica de lado até doer
Ninguém coloca rate limit no app no primeiro dia. Você está testando com três abas do navegador e uma coleção do Postman, e toda requisição parece legítima porque é. Aí o app vai ao ar, e em uma semana o script de alguém está martelando sua rota /api/login testando cada senha de uma lista vazada, ou o crawler de um concorrente está sugando seu catálogo inteiro de produtos por um endpoint sem autenticação.
Vi isso acontecer com um fundador que lançou uma página de lista de espera numa sexta-feira e acordou na segunda com onze mil cadastros falsos vindos das mesmas três faixas de IP, todos tentando pegar bônus de indicação. O conserto levou vinte minutos. A limpeza tomou o resto da semana.
As rotas que são atacadas primeiro
Atacantes não escaneiam ao acaso — eles vão atrás das rotas que são baratas para eles e caras para você. Login e cadastro (credential stuffing), redefinição de senha (email bombing), busca (carga no banco de dados), e qualquer coisa que chame um modelo de IA ou uma API paga de terceiros (abuso de custo, sem meias palavras). Se seu app tem um botão "gerar" que chama um LLM, esse botão é o alvo mais valioso do site inteiro para quem quer estourar sua fatura.
O que realmente funciona
Um rate limiter é só um contador com uma janela de tempo, mas onde você coloca o contador e o que você usa como chave muda tudo.
Use mais do que só o IP como chave. Limitar só por IP quebra no momento em que alguém está atrás de um NAT corporativo (você vai limitar o escritório inteiro) ou um atacante gira por um pool de proxies residenciais (você nem vai pegar ele). Coloque em camadas: um limite frouxo por IP como primeiro filtro, depois um limite mais apertado por ID de usuário ou sessão para qualquer coisa pós-login, já que isso é um valor que um atacante não consegue forjar tão fácil.
Deixe as rotas que chamam IA como as mais rígidas. Uma rota de API típica pode razoavelmente permitir 100 requisições por minuto por usuário. Uma rota que dispara uma chamada ao GPT-4 ou ao Claude provavelmente deveria permitir algo perto de 5 a 10, porque cada chamada custa dinheiro de verdade e um script descontrolado pode queimar o orçamento de IA de um dia inteiro em uns noventa segundos. Trate "chama um modelo pago" como uma camada própria, não como um caso especial do seu limite geral de API.
Falhe fechado na autenticação, falhe aberto na navegação. Se o armazenamento do seu rate limiter (geralmente Redis) tiver um problema, decida com antecedência o que acontece: para tentativas de login, bloqueie por padrão quando você não conseguir checar a contagem — é melhor um falso positivo do que uma porta aberta. Para páginas de leitura pesada, como um blog público ou uma listagem de produtos, falhe aberto, porque uma queda no rate limiter não deveria derrubar o site inteiro por causa de uma visualização de página.
Onde o contador realmente mora
Contadores em memória não sobrevivem a um reinício do servidor nem funcionam entre várias instâncias, então o contador precisa morar em algum lugar compartilhado — Redis é a escolha padrão, com um algoritmo de janela deslizante ou token bucket e um TTL curto em cada chave para que contagens antigas expirem sozinhas. O Redis da Upstash funciona bem aqui especificamente porque dá para usar de funções edge sem dor de cabeça com pool de conexões, o que importa se você quer bloquear abuso antes que ele chegue perto da lógica principal do seu app.
Uma comparação: rate limiting simples vs. em camadas
| Aspecto | Limite global único | Limites em camadas, por endpoint |
|---|---|---|
| Força bruta no login | Mesmo orçamento que a navegação normal | Limite apertado, chaveado por IP + par de usuário |
| Rotas que chamam IA/LLM | Sem tratamento especial | Camada própria e restrita, separada da API geral |
| Usuários avançados legítimos | Limitados junto com todo mundo | Limites maiores depois de autenticados e confiáveis |
| Exposição a custo | Sem limite até alguém notar a fatura | Contida perto da origem |
| Overhead operacional | Baixo — uma regra só | Um pouco maior, mas cada regra é simples |
Onde isso vive em um app construído com a Greta
Como um app gerado pela Greta roda em Next.js com um backend de verdade, o rate limiting fica no mesmo lugar que qualquer proteção de produção — middleware ou handlers de rota de API, não colado depois como um remendo. Combina bem com o padrão de jobs em fila de rodando jobs em segundo plano e tarefas agendadas: depois que uma requisição passa pela checagem de limite, trabalho caro como uma geração por IA ou um envio de e-mail em massa ainda pode ser jogado numa fila em vez de rodar na hora, então um pico de tráfego legítimo degrada com elegância em vez de travar por timeout.
Se o seu app aceita webhooks de entrada, o mesmo instinto vale ali também — rate limiting é a primeira linha de defesa, e a verificação de assinatura (que a gente cobriu em conectando webhooks e APIs de terceiros) é a segunda. Você quer as duas, porque uma enxurrada de requisições que parece válida mas não está assinada nunca deveria chegar perto da sua lógica de negócio.
Perguntas frequentes
Preciso de rate limiting antes de ter usuários de verdade? Você precisa antes de ter uma URL pública. Bots encontram domínios novos em horas, não semanas, e um formulário de cadastro ou contato sem limite algum é um convite aberto, não importa quanto tráfego você acha que tem.
Qual é um limite razoável para uma rota de API típica? Não existe um número universal, mas um ponto de partida comum é algo em torno de 60 a 100 requisições por minuto por usuário autenticado em rotas normais, e dígitos únicos por minuto para qualquer coisa cara. Observe o tráfego real no primeiro mês e ajuste a partir daí — é mais fácil afrouxar um limite apertado demais do que limpar a bagunça de um que foi frouxo demais.
Rate limiting vai incomodar usuários legítimos? Só se você configurar de forma agressiva demais ou usar a chave errada. Um limite generoso que só entra em ação em padrões claros de abuso é invisível para usuários reais. As reclamações costumam vir de limites só por IP pegando redes compartilhadas, algo que um limite em camadas e consciente do usuário evita.
Um CAPTCHA sozinho já resolve? Não — CAPTCHAs param bots menos sofisticados, mas não fazem nada contra um atacante determinado com serviços de resolução automática, e ainda adicionam atrito para cada usuário real. Use rate limiting como a defesa de verdade e um CAPTCHA como uma lombada extra nos seus formulários de maior risco, não como substituto.
Encerramento
Rate limiting é uma daquelas coisas chatas até o momento em que deixa de ser, e aí você está lendo logs às duas da manhã tentando entender por que a fatura de IA tem um dígito a mais do que deveria. Coloque um contador na frente das suas rotas de autenticação e das que chamam IA antes do lançamento, use como chave algo que um atacante não consiga forjar barato, e ele faz o trabalho dele em silêncio enquanto você foca no resto.
