Verificação de Assinatura

Todos os payloads de webhook são assinados com HMAC-SHA256 para que você possa verificar que a requisição veio do SimpleCRM e não foi alterada.

1. Obtenha o Secret

Ao criar um webhook na interface web do SimpleCRM, um secret é gerado automaticamente (formato: whsec_...).

Importante: O secret é exibido apenas uma vez, no momento da criação. Copie e armazene-o em local seguro (ex: variável de ambiente no seu servidor).

Você pode encontrar o secret na tela de Configurações → Webhooks da aplicação web. Se perdeu o secret, delete o webhook e crie um novo.

2. Como Assinamos

Concatenamos o timestamp e o body cru da requisição, separados por um ponto, e geramos um HMAC-SHA256 usando seu secret:

Algoritmo
message = "{timestamp}.{raw_body}"
signature = HMAC-SHA256(secret, message)
header = "sha256={signature}"

O resultado é enviado no header X-Webhook-Signature.

3. Exemplo de Verificação

Node.js

const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signature, timestamp, secret) {
  const message = timestamp + '.' + rawBody;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');

  const expected = 'sha256=' + expectedSignature;
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// No seu endpoint de webhook:
app.post('/webhooks/simplecrm', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const rawBody = JSON.stringify(req.body);

  if (!verifyWebhookSignature(rawBody, signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Assinatura válida - processar evento
  const { event, data } = req.body;
  console.log('Evento recebido:', event, data);
  res.status(200).json({ received: true });
});

Python

import hmac
import hashlib

def verify_webhook_signature(raw_body, signature, timestamp, secret):
    message = f"{timestamp}.{raw_body}"
    expected = "sha256=" + hmac.new(
        secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Segurança: Sempre use comparação em tempo constante (como timingSafeEqual ou compare_digest) para evitar ataques de timing. Valide também o timestamp para rejeitar eventos antigos (recomendado: rejeitar se > 5 minutos).

Este site utiliza cookies

Utilizamos cookies essenciais para o funcionamento da plataforma e cookies de análise para melhorar sua experiência. Ao continuar navegando, você concorda com nossa Política de Privacidade e Termos de Uso.