Como funciona a verificação da assinatura de um webhook
A assinatura de um webhook é uma prova concisa de que o evento veio do provedor de pagamentos, e não de uma solicitação POST aleatória. O provedor assina o payload com um segredo compartilhado ou uma chave privada, e o seu aplicativo verifica essa assinatura antes de confiar no evento. Se a assinatura for inválida, a resposta mais segura é 401 ou 400, sem atualizar o pedido. Para entender como verificar a assinatura de um webhook, o primeiro passo é conferir qual método e quais dados o provedor exige.
Parece simples. Raramente é.
Na prática, a verificação da assinatura protege você contra faturas falsificadas, reembolsos fraudulentos e payloads adulterados que, à primeira vista, parecem legítimos. Um webhook que informa “pagamento concluído” não serve de nada se qualquer pessoa puder falsificá-lo. Para equipes que usam um guia de gateway de pagamento com criptomoedas para e-commerce, essa verificação fica entre a aceitação do pagamento e o processamento do pedido. Por isso, uma suposição equivocada pode interromper todo o fluxo.
A maioria dos provedores assina o corpo bruto completo, um carimbo de data e hora, ou ambos. Alguns usam HMAC-SHA256; outros, um cabeçalho versionado com vários valores de assinatura. Basta uma divergência. O provedor pode estar certo, mas o seu aplicativo ainda assim pode rejeitar o evento se você alterar um único byte.
Primeiro, confirme se o problema está mesmo relacionado à assinatura
Os logs devem permitir identificar isso em menos de 5 minutos. Se não permitirem, não são detalhados o suficiente.
Comece pelo código de resposta exato e pelo texto do erro. Um 400 com a mensagem “assinatura inválida” indica uma coisa; um 500 ou um timeout indica outra. Um erro de assinatura inválida no webhook pode apontar para uma divergência no segredo, no corpo ou no cabeçalho. Falhas na entrega, rotas incorretas, erros de TLS e timeouts de proxy podem parecer problemas de webhook no painel, mas não são a mesma coisa. Se o provedor mostra “entregue” e o seu endpoint retorna 200, provavelmente a verificação da assinatura não é a causa do problema.
Confira três coisas em conjunto: o log de entrega do provedor, o log do seu aplicativo e o log do proxy reverso, se houver. Uma solicitação que nunca chega ao seu código não pode falhar na verificação da assinatura. Uma solicitação que chega ao seu código, mas retorna 401, provavelmente pode. Um detalhe importante: se o evento aparece nos logs, mas não há erro de assinatura, talvez o seu código esteja rejeitando o payload mais adiante, depois da etapa de verificação.
Em resumo: confirme o sintoma antes de alterar o código.
Confira o segredo compartilhado ou a chave de assinatura
Este é o erro mais comum — e é tão banal que pode passar despercebido. O segredo do webhook no seu aplicativo precisa corresponder exatamente ao segredo atual no painel de pagamentos, inclusive eventuais espaços ocultos copiados de um campo de texto. Se o provedor trocou o segredo na terça-feira passada, a chave antiga continuará no seu ambiente até alguém atualizá-la.
Compare o segredo no painel com o que está no ambiente de implantação, não apenas no seu computador. Produção, homologação e desenvolvimento local devem ter valores próprios. Uma equipe que copia um segredo de teste para produção pode passar 2 horas investigando uma falha de assinatura causada por uma única string colada no lugar errado. Esse tipo de problema é comum durante o lançamento e nas migrações de um processador para outro. Para equipes que usam um guia de gateway de pagamento com criptomoedas para e-commerce, divergências de segredo costumam aparecer logo após uma nova versão do checkout.
Mantenha as chaves antigas somente se o provedor aceitar a rotação de chaves com um período de sobreposição. Se as chaves antiga e nova forem válidas ao mesmo tempo por um curto período, o verificador deve tentar primeiro a chave ativa e depois a anterior. Se o provedor não aceitar sobreposição, remova a chave antiga de todos os ambientes. Não tente adivinhar.
Reconstrua o corpo bruto da solicitação exatamente como foi recebido
É aqui que muitas implementações bem-feitas falham. Em geral, as verificações de assinatura dependem dos bytes brutos exatos enviados pelo provedor, não do objeto JSON que o framework produz após o processamento. Se o seu código converter números, reordenar campos, remover espaços em branco ou normalizar quebras de linha, a assinatura calculada pode mudar, mesmo que o payload “pareça” idêntico.
Alguns frameworks leem o corpo uma vez e depois descartam o fluxo original. Outros processam o JSON automaticamente antes de executar o middleware. Isso significa que o verificador recebe um objeto reconstruído, não o corpo bruto. Em geral, a solução é capturar primeiro o payload intacto e, em seguida, passar esse mesmo buffer para a função de verificação da assinatura. Uma configuração do framework pode determinar se o corpo será preservado ou reescrito.
Por exemplo, um payload com 14 campos pode chegar em uma ordem específica de bytes que o seu código nunca verá se o analisador ordenar as chaves. Uma quebra de linha no final pode fazer diferença. Uma única conversão para UTF-8 também. Sim, um único caractere invisível pode comprometer toda a verificação.
Se a sua stack permitir, registre o tamanho do corpo e um hash do corpo bruto da solicitação antes do processamento. Não registre segredos. Registre, sim, o caminho exato do código que lê o fluxo. Assim, fica muito mais fácil entender por que testar um pagamento com criptomoedas às vezes funciona no Postman, mas falha com um webhook real do provedor.
Valide o carimbo de data e hora, a sincronização do relógio e a proteção contra repetição
Muitos esquemas de webhook incluem um carimbo de data e hora para impedir que eventos antigos sejam reenviados mais tarde. O verificador pode rejeitar uma solicitação se o horário estiver fora de uma janela de tolerância, geralmente de 5 minutos ou de outro limite definido pelo provedor. Isso protege contra ataques de repetição, mas também significa que o relógio do servidor precisa estar correto.
Confira o relógio do sistema em todos os servidores que recebem webhooks. Se o relógio estiver adiantado ou atrasado em 3 minutos, a assinatura pode falhar mesmo que o payload esteja correto. Se o servidor estiver em um contêiner, verifique também o horário do host. O NTP ou outro serviço de sincronização de horário deve estar ativo na máquina que realiza a verificação. Um servidor com 10 minutos de diferença pode transformar um webhook válido em uma falsa falha.
A proteção contra repetição também é importante. Se o seu código armazena em cache as assinaturas ou os IDs de evento já vistos, confira se o TTL do cache corresponde à janela de repetição esperada pelo provedor. Uma entrada antiga no cache pode fazer com que uma nova tentativa válida de entrega seja rejeitada. Uma nova tentativa do provedor não é o mesmo que uma repetição maliciosa, então o código deve saber lidar com os dois casos. É um detalhe pequeno, mas com grandes consequências.
Confira se o cabeçalho da assinatura está sendo interpretado corretamente
Os cabeçalhos de assinatura não têm todos o mesmo formato. Alguns provedores enviam um cabeçalho com um único hash; outros enviam uma lista de pares de chave e valor separados por vírgulas, um rótulo de versão e um carimbo de data e hora. O seu analisador precisa corresponder exatamente a esse formato. Se ele espera v1=, mas o provedor envia t= e várias versões, a verificação falhará antes mesmo de começar a parte criptográfica.
Cuidado com erros de remoção de espaços. Espaços no início ou no fim fazem diferença. Erros de codificação também podem ocorrer quando um framework decodifica cabeçalhos como Latin-1 em vez de UTF-8. Uma quebra de linha perdida em uma variável de ambiente pode fazer a comparação falhar. Não normalize o cabeçalho, a menos que o provedor permita. Não converta para minúsculas um valor que precise ser compatível com dados binários. Esses dois deslizes causam mais problemas do que deveriam.
Também é preciso ter cuidado ao lidar com vários esquemas. Alguns provedores publicam uma assinatura atual e outra anterior durante períodos de transição. O verificador deve saber qual versão está usando e rejeitar versões desconhecidas de forma clara. Se o cabeçalho incluir tanto um carimbo de data e hora quanto uma assinatura, verifique ambos. Se o provedor documentar um prefixo para assinatura, use-o exatamente como está descrito. Para saber mais sobre como proteger webhooks, consulte as melhores práticas de segurança para pagamentos com criptomoedas.
Teste com um evento de webhook comprovadamente válido
Um evento comprovadamente válido poupa tempo. Reenvie um evento pelo painel do provedor ou use um payload de exemplo documentado e compare a assinatura esperada com a que o seu código calcula. Se o exemplo for validado, mas o tráfego real não, o problema provavelmente está na configuração, no ambiente ou na rotação do segredo. Se nenhum dos dois passar, o problema está no caminho de execução do código.
Use um único ID de evento e um único carimbo de data e hora. Em seguida, compare quatro itens: corpo bruto, valor do cabeçalho, segredo e relógio. Isso basta para identificar a maioria das falhas. Um payload de teste copiado para um arquivo local pode conter formatação que o endpoint real nunca recebe. Por isso, prefira sempre a ferramenta de reenvio do provedor, quando disponível. Um reenvio vale mais do que 20 tentativas no escuro.
Se o provedor oferecer uma ferramenta para calcular assinaturas, use o mesmo payload nela. Se o resultado diferir por um único caractere, há um problema na interpretação ou na preservação do corpo. Se o resultado corresponder, mas o provedor ainda rejeitar a solicitação, o problema está no segredo ou na interpretação do cabeçalho. Essa distinção indica onde procurar em seguida.
Esse também é o momento de separar claramente os ambientes de homologação e produção. Um evento de homologação enviado com um segredo de produção vai falhar sempre, e a falha parecerá uma assinatura inválida até você conferir o rótulo do ambiente.
Reforce e monitore o endpoint do webhook
Depois que a verificação da assinatura funcionar, mantenha-a funcionando. Registre o ID do evento, o resultado da verificação, o nome do provedor e o nome do ambiente. Não registre o segredo completo. Não registre o corpo bruto completo se ele contiver dados confidenciais de clientes. Use uma mensagem de erro curta e clara para os operadores e uma resposta simples de rejeição para o provedor.
Troque o segredo do webhook periodicamente e documente o processo. Uma rotação em 2 etapas é mais segura: adicione a chave nova, confirme que ambas funcionam, se houver suporte à sobreposição, e depois remova a antiga. Separe os endpoints de teste e produção para evitar que um erro em homologação afete pedidos reais. Parece óbvio, mas as equipes ainda os confundem.
Configure alertas para um aumento repentino de falhas de assinatura, não para uma única tentativa malsucedida. Uma falha pode ser uma nova tentativa com problemas. Cinco falhas em 1 minuto merecem atenção. Inclua no alerta a rota, o provedor e o código de resposta, para que a pessoa de plantão consiga identificar se o problema é uma divergência de segredo, um erro no analisador ou no relógio. Se ainda estiver configurando o endpoint, o artigo como configurar pagamentos com criptomoedas pode ajudar a manter simples o fluxo do webhook desde o início.
Por fim, mantenha um pequeno guia operacional com as etapas exatas para corrigir uma assinatura inválida de webhook de pagamento com criptomoedas, incluindo onde fica o segredo, como reenviar um evento e qual linha do log confirma a verificação. Para documentar como validar webhook de pagamento, inclua também os critérios para conferir o corpo bruto, o cabeçalho, o segredo e o carimbo de data e hora. Um guia de 10 linhas pode poupar uma hora às 2 da manhã.




Comments