Qualquer pessoa com acesso à URL do seu webhook pode simular uma entrega. Por isso, a SocialSell assina cada requisição com HMAC-SHA256 usando o secret da sua assinatura — e você deve validar essa assinatura antes de processar qualquer payload.
Cada entrega inclui o header:
X-SocialSell-Signature: sha256=a1b2c3d4e5f6789...
O valor é sha256= seguido do HMAC-SHA256 do corpo bruto da requisição, usando o secret da assinatura como chave.
Como validar
Sempre use o corpo bruto (raw bytes) da requisição, não o JSON parseado. Re-serializar o JSON pode alterar a assinatura.
Node.js (Express)
Python (Flask)
Python (Django)
TypeScript (Fastify)
const crypto = require ( 'crypto' );
const express = require ( 'express' );
const app = express ();
// Use express.raw() para receber o corpo como Buffer
app . post ( '/webhooks/socialsell' , express . raw ({ type: 'application/json' }), ( req , res ) => {
const signature = req . headers [ 'x-socialsell-signature' ];
const secret = process . env . SOCIALSELL_WEBHOOK_SECRET ;
if ( ! isValidSignature ( req . body , signature , secret )) {
return res . status ( 401 ). json ({ error: 'Assinatura inválida' });
}
const event = JSON . parse ( req . body );
console . log ( 'Evento recebido:' , event . event );
// processar evento...
res . status ( 200 ). send ( 'OK' );
});
function isValidSignature ( body , signature , secret ) {
const expected = 'sha256=' + crypto
. createHmac ( 'sha256' , secret )
. update ( body )
. digest ( 'hex' );
// timingSafeEqual previne timing attacks
try {
return crypto . timingSafeEqual (
Buffer . from ( signature ),
Buffer . from ( expected )
);
} catch {
return false ;
}
}
Erros comuns de validação
Problema Causa Solução Assinatura sempre inválida Corpo sendo parseado antes da validação Use o corpo bruto (raw buffer) timingSafeEqual lançando erroStrings de tamanho diferente Confirme que o secret está correto Validação falhando em produção secret com espaços ou quebra de linhaVerifique a variável de ambiente com trim() Funcionou local, falha em produção Proxy modificando o corpo Configure o proxy para não modificar o payload
Boas práticas de segurança
Sempre valide antes de processar — nunca confie no payload sem verificar a assinatura
Use timingSafeEqual — previne timing attacks onde um atacante mede o tempo de comparação para adivinhar a assinatura
Armazene o secret como variável de ambiente — nunca no código ou em repositórios
Rejeite com 401 — não com 200. Responder com sucesso a payloads inválidos pode confundir sistemas de monitoramento
Rotacione o secret se comprometido — delete a assinatura e crie uma nova com POST /v1/webhooks