
Segurança de webhook do WhatsApp: assinatura, replay e limites
Como proteger o webhook do WhatsApp que alimenta seu agente de IA: validar a assinatura da Meta, evitar replay e aplicar limites de taxa.
Quer aplicar isso na sua empresa?
Agendar conversa com o Juan →Segurança de webhook do WhatsApp: assinatura, replay e limites
Para proteger o webhook do WhatsApp que alimenta um agente de IA, valide a assinatura X-Hub-Signature-256 sobre o corpo bruto da requisição usando o segredo do app da Meta, descarte eventos repetidos pelo identificador da mensagem e aplique limites de taxa e de tamanho antes de qualquer chamada ao modelo. Essas três camadas impedem que alguém forje mensagens, reaproveite requisições legítimas ou esgote sua operação. A ordem importa: autenticar, deduplicar, limitar e só então entregar o evento ao agente.
Principais pontos
- A assinatura prova que a requisição veio da Meta e não foi alterada, mas só funciona se for calculada sobre os bytes originais do corpo.
- O webhook entrega eventos pelo menos uma vez, então repetição é comportamento normal e a deduplicação por identificador é obrigatória.
- Limites de taxa devem agir depois da validação e, de preferência, na fila do agente, para não provocar reenvios e perda de mensagens.
- Assinatura válida não torna o conteúdo seguro: o texto do cliente continua sendo entrada não confiável para o modelo.
- Registre decisões (aceito, rejeitado, duplicado, limitado) sem gravar dados pessoais desnecessários, em linha com a LGPD.
Por que o webhook é a porta mais sensível do agente?
O endpoint de webhook é uma URL pública na internet. Qualquer pessoa que a descubra pode enviar uma requisição com aparência de mensagem do WhatsApp. Se o seu agente confia nesse corpo, um atacante pode simular um cliente, acionar fluxos internos, gerar custo de modelo ou provocar respostas para números que nunca escreveram.
Em um agente de atendimento, o risco cresce porque o webhook não termina em uma tabela de log: ele dispara raciocínio, consulta a sistemas e, às vezes, envia mensagens. Por isso tratamos o endpoint como uma fronteira de segurança, não como um detalhe de integração. Para o contexto geral da integração, veja como integrar IA no WhatsApp da sua empresa.
Uma observação sobre fontes: o que descrevemos sobre cabeçalho, segredo e algoritmo vem da documentação oficial da Meta. As recomendações de deduplicação e de limites são prática de engenharia comum em webhooks, e marcamos como hipótese o que depende do seu volume e da sua infraestrutura.
Como validar a assinatura da Meta, passo a passo
A Meta assina cada notificação com um HMAC SHA-256 do corpo da requisição, calculado com o segredo do app, e envia o resultado no cabeçalho X-Hub-Signature-256, com o prefixo sha256=. Sua tarefa é recalcular o valor e comparar.
- Leia o corpo bruto da requisição como bytes, antes de qualquer parser de JSON.
- Obtenha o segredo do app (App Secret) em um cofre de segredos ou variável de ambiente protegida. Não use o token de verificação nem o token de acesso para isso.
- Calcule o HMAC SHA-256 dos bytes com esse segredo e converta para hexadecimal.
- Monte a string esperada com o prefixo sha256= e compare com o cabeçalho usando comparação em tempo constante.
- Se o cabeçalho estiver ausente, malformado ou diferente, rejeite a requisição com um erro genérico e não processe nada.
- Só depois de validar, faça o parse do JSON e siga o fluxo.
O erro mais comum é validar sobre o JSON já interpretado e reserializado. Mudanças de espaçamento, ordem de chaves ou escape de caracteres acentuados alteram os bytes e fazem a assinatura legítima falhar. Em português isso aparece rápido, porque nomes e mensagens têm acentos e emojis. Muitos frameworks consomem o corpo antes do seu código; configure o servidor para guardar uma cópia dos bytes originais.
Outros cuidados de implementação:
- Nunca registre o segredo em logs nem o envie para ferramentas de monitoramento.
- Planeje a troca do segredo: defina quem pode rotacioná-lo e como o serviço recarrega o valor sem ficar fora do ar.
- Em ambientes de teste, use um app e um segredo separados dos de produção.
A documentação oficial da Meta sobre webhooks do Graph API descreve esse mecanismo e é a referência final para o formato do cabeçalho. Como comparação de um padrão semelhante em outro provedor, a documentação de webhooks da Stripe mostra a mesma lógica de assinatura sobre o corpo bruto.
O que a verificação inicial do endpoint faz e não faz?
Ao cadastrar a URL no painel da Meta, ela envia uma requisição GET com os parâmetros hub.mode, hub.verify_token e hub.challenge. Seu endpoint compara o token de verificação com o valor que você definiu e devolve o desafio recebido. Isso confirma que você controla a URL.
Essa etapa não autentica as notificações seguintes. O token de verificação é um segredo de configuração, e as mensagens reais chegam por POST, protegidas pela assinatura. Dois pontos práticos: responda ao GET de verificação apenas quando o token bater, e nunca aceite POST sem checar a assinatura só porque a verificação inicial passou.
Se o seu número ainda depende da conta empresarial, vale conferir o processo de verificação de empresa na Meta para a API do WhatsApp, que antecede a configuração do webhook em produção.
Como se proteger contra repetição (replay)?
Há dois tipos de repetição, e eles pedem respostas diferentes.
O primeiro é a repetição legítima. Se o seu endpoint demora ou devolve erro, a Meta tenta entregar de novo. Isso significa que o mesmo evento pode chegar mais de uma vez. O segundo é a repetição maliciosa: alguém captura uma requisição válida (por exemplo, em um log mal protegido) e a reenvia. Nos dois casos a assinatura continua correta, porque o corpo é idêntico. Por isso assinatura sozinha não impede replay.
Até onde a documentação oficial indica, a notificação não traz um carimbo de tempo assinado separado em cabeçalho. A defesa prática é a idempotência: tratar cada evento uma única vez.
- Escolha a chave de deduplicação: para mensagens recebidas, o identificador da mensagem (wamid); para atualizações de status, combine o identificador e o status.
- Grave a chave de forma atômica, com restrição de unicidade no banco ou operação de inserir se ausente em um cache. Verificar e depois gravar em dois passos abre espaço para corrida.
- Se a chave já existir, responda com sucesso e não reprocesse. Responder com erro só estimula novas tentativas.
- Mantenha as chaves por tempo maior que o período em que a Meta pode reenviar. O valor exato depende da documentação vigente e da sua tolerância; trate como parâmetro a revisar.
- Valide também que o identificador do número (phone_number_id) no payload é um dos seus. Eventos de outro número não devem entrar no fluxo.
Há uma segunda camada: efeitos colaterais idempotentes. Mesmo com deduplicação na entrada, uma falha no meio do processamento pode levar a uma nova tentativa interna. Se o agente cria um agendamento ou envia uma resposta, grave a intenção com uma chave própria para não executar a ação duas vezes. A documentação da Stripe sobre requisições idempotentes é um bom exemplo de como um provedor define esse contrato, e a ideia se aplica às suas próprias ações.
Sobre rejeitar eventos antigos pelo timestamp que vem dentro do payload: como o corpo está assinado, o valor é confiável. Mas descartar por idade pode perder entregas tardias legítimas. Nossa hipótese de trabalho é registrar e sinalizar eventos muito antigos em vez de rejeitá-los automaticamente, até você observar o comportamento real do seu volume.
Como aplicar limites de taxa sem perder mensagens?
Limite de taxa em webhook tem uma armadilha: se você devolve erro para a Meta por excesso de volume, ela tenta novamente, e a carga volta. Rejeitar na porta é útil contra tráfego não autenticado, mas para tráfego autenticado o limite deve agir mais adiante.
Pense em camadas:
- Antes da assinatura: limite de tamanho do corpo e de tempo de leitura. Corpos enormes ou conexões lentas são descartados cedo, com custo mínimo.
- Tráfego sem assinatura válida: contador por origem e bloqueio temporário de quem insiste. Como os endereços de origem da Meta podem mudar, tratar uma lista fixa de IPs como única proteção é frágil. Use como reforço opcional, não como substituto da assinatura.
- Depois da assinatura e da deduplicação: aceite o evento, responda rápido com sucesso e coloque-o em uma fila. O limite real fica aqui.
- Por remetente: um teto de mensagens processadas por número de cliente em uma janela de tempo. Isso contém laços (um bot do outro lado conversando com o seu) e abuso que geraria custo de modelo.
- Global: concorrência máxima de chamadas ao modelo e orçamento diário de uso com alerta. Ao atingir o teto, o agente responde com uma mensagem curta de espera ou encaminha para um humano.
Os valores dos tetos dependem do seu fluxo e não existe número universal. Comece com um limite conservador, meça no piloto e ajuste. Para o lado do custo, o raciocínio de métricas por unidade ajuda a definir o que é um teto razoável por conversa.
E o conteúdo da mensagem, depois que a assinatura passou?
A assinatura garante origem e integridade, não intenção. Um cliente real, ou alguém usando o número de um cliente, pode enviar um texto que tenta induzir o agente a ignorar regras, revelar dados ou executar uma ação. Tratamos o texto do WhatsApp sempre como entrada não confiável.
O OWASP mantém uma lista dos principais riscos para aplicações com LLM, incluindo injeção de prompt e excesso de autonomia do agente. O caminho prático é limitar o que o agente pode fazer (ferramentas restritas, permissões mínimas, aprovação humana para ações sensíveis) e validar saídas e ações. Detalhamos isso em guardrails para agentes de IA. Para quem expõe também um gateway de agente, o checklist de segurança do OpenClaw Gateway segue a mesma ideia de evidência antes da exposição.
Sobre dados pessoais: o payload contém número de telefone, nome de perfil e texto. Guarde apenas o necessário nos logs, mascare números quando possível e defina prazo de retenção. A ANPD é a referência institucional para orientações de LGPD no Brasil.
Cenário ilustrativo: o mesmo evento chega duas vezes
Cenário ilustrativo: uma loja usa um agente no WhatsApp para informar o status de pedidos. O servidor demora a responder por causa de uma consulta lenta ao ERP, e a Meta entrega a mesma mensagem novamente.
Sem proteção, o agente processa as duas cópias, consulta o sistema duas vezes e responde ao cliente com duas mensagens quase iguais. Se a mensagem fosse um pedido de reagendamento, o sistema poderia registrar a ação em duplicidade.
Com as camadas descritas: a primeira requisição passa pela assinatura, grava o identificador da mensagem e entra na fila. A segunda também passa pela assinatura, mas o identificador já existe, então recebe sucesso imediato e é descartada. O log registra duplicado, sem texto da mensagem. O agente responde uma vez, e a ação de reagendamento carrega uma chave própria que impede a segunda execução.
Checklist de revisão antes de ir para produção
- A assinatura é validada sobre o corpo bruto, com comparação em tempo constante.
- O segredo do app está em cofre, é distinto entre ambientes e tem responsável por rotação.
- Requisições sem assinatura válida são rejeitadas antes de qualquer parse ou consulta.
- Existe deduplicação atômica por identificador, com retenção definida.
- O endpoint responde rápido e processa o resto em fila.
- Há limite de tamanho, limite por remetente, concorrência máxima e alerta de orçamento.
- Os logs registram decisão e identificador, sem texto completo nem número completo.
- Ações do agente com efeito externo são idempotentes e passam por permissões mínimas.
- Existe um caminho de handoff humano quando um limite é atingido.
Como esse trabalho entra no método
No método que seguimos, o webhook aparece nas quatro etapas. Em mapear, desenhamos o caminho do evento, da Meta até a ação do agente, e listamos o que cada etapa pode acessar. Em limitar, definimos assinatura, deduplicação, tetos e permissões. Em pilotar, rodamos um fluxo real com logs e um critério de sucesso combinado, incluindo testes de assinatura inválida, evento repetido e pico de volume. Em transferir, entregamos o runbook, os alertas e a decisão de expandir, ajustar ou parar. Quando a operação é gerenciada, esse acompanhamento é feito pela Be Human.
Para envios iniciados pela empresa, que seguem regras próprias de consentimento e modelos, veja mensagens ativas no WhatsApp: templates e opt-in.
Perguntas frequentes
Preciso validar a assinatura se o endpoint usa HTTPS e uma URL difícil de adivinhar? Sim. HTTPS protege o trânsito e uma URL obscura não é um segredo confiável, pois pode vazar em logs, configurações e ferramentas de monitoramento. A assinatura é o que prova que a Meta enviou aquele corpo exato.
Qual segredo uso para calcular a assinatura? Use o segredo do app (App Secret) do aplicativo configurado na Meta. O token de verificação serve apenas ao handshake inicial do GET, e o token de acesso serve para chamar a API, não para assinar nem validar notificações.
A assinatura válida impede replay? Não. Uma requisição legítima reenviada continua com assinatura correta, porque o corpo é o mesmo. A proteção vem da deduplicação pelo identificador da mensagem, de preferência com gravação atômica e retenção maior que o período de reenvio.
Devo devolver erro quando o limite de taxa for atingido? Para tráfego sem assinatura válida, sim. Para eventos autenticados, prefira aceitar, enfileirar e aplicar o limite no processamento, porque erros provocam novas tentativas da Meta e podem aumentar a carga. Quando o teto for atingido, responda com uma mensagem de espera ou encaminhe para uma pessoa.