Documentação B2B

Verificação de Autenticidade

Para garantir que cada notificação recebida foi enviada exclusivamente pela Creditas e não foi alterada no caminho, utilizamos o padrão HTTP Message Signatures. Este mecanismo utiliza assinaturas digitais (HMAC) para fornecer integridade e autenticidade ponta a ponta.

1. Obtenção da Chave Secret

Antes de validar as mensagens, você precisará da sua Secret Key.

  1. Após o registro nos eventos, você receberá um magic-link.
  2. Este link é uma URL para uma requisição via POST que retornará sua chave.
🚧

Atenção: Acesso Único Por questões de segurança, a URL do magic-link pode ser acessada apenas uma vez. Guarde sua chave secret em um local seguro (como um Vault ou Environment Variable). Caso a perca, será necessário solicitar um novo link ao seu consultor.

Exemplo:

curl --location --request POST 'https://webhook.stg.creditas.io/webhook/secret/058a18f8-071a-4018-b627-f6791d1b48f0/unwrap' \
--header 'Accept: application/vnd.creditas.v1+json'
{
    "secret": "d0a0a44ffb394a4841bf88df5ecc4625"
}
{
    "code": "CONSUMER_SECRET_ALREADY_CHECKED",
    "message": "Secret already checked.",
    "timestamp": "2023-05-11T12:08:50.756622"
}

2. Como Validar a Mensagem

Sempre que receber um Webhook, sua aplicação deve seguir estes passos para validar a assinatura antes de processar o conteúdo:

PassoAçãoDescrição
1Capturar HeadersObtenha os valores de digest, signature e signature-inputda requisição
2Validar AlgoritmoVerifique se o campo alg no header signature-input é hmac-sha256
3Reconstruir o InputMonte a string de verificação utilizando o digest, a @target-uri (seu endpoint) e os metadados (created e nonce)
4Gerar Local HMACGere uma assinatura local usando sua Secret Key sobre a string montada
5CompararCompare sua assinatura gerada com o valor recebido no header signature.

Resultado da Validação:

  • Assinaturas Coincidentes: A mensagem é autêntica e pode ser processada.
  • Assinaturas Diferentes: A mensagem deve ser considerada não autêntica e descartada imediatamente.
❗️

Caso as assinaturas não coincidam, a mensagem pode ter sido modificada no caminho ou pode ter sido enviada por alguém que não tem a chave privada correspondente à chave pública do emissor, ou seja, não foi enviada pela Creditas. Nesse caso, a mensagem deve ser considerada não autêntica e não deve ser processada.

3. Exemplo de Implementação

Abaixo, um exemplo simplificado da lógica de validação:

const crypto = require('crypto');

// 1. Headers recebidos:
// O header "Signature" da mensagem HTTP recebida contém a assinatura da mensagem. 
// O header "Signature-input" é um campo dicionário que contém metadados da mensagem assinada, como o algoritmo de assinatura usado, a chave pública do emissor entre outros.

const headers = {
  digest: 'SHA-256=8df2bffaf24313e75ace59688f2592993d2f990e5f5c9caea851c656492f9c83',
  host: '3a2924a6a9dfb9aa173f5512cf2d54aa.m.pipedream.net',
  signature: 'webhook-param=:6974557af18a1925179c17c30e4239e8b9d68e883b2d3e13fb5498f85df3d858:',
  signature-input: 'webhook-param=("digest" "@target-uri");created=1677784215510;nonce="a8ca9147-f71d-4b02-b229-5f1a5dbb753b";alg="hmac-sha256"'
};

// 2. 'Parse' dos valores do header signature-input.
const sigInput = headers['signature-input'].split(';').reduce((prev, curr) => {
  const [key, value] = curr.split('=');
  prev[key] = value.replace(/"/g, '');
  return prev;
}, {});

// 3. Separar a Signature em seu valor e parâmetros
const [sigVal, sigParams] = headers.signature.split(':');

// 4. Verificar se a Signature usa o algoritmo esperado
if (sigInput.alg !== 'hmac-sha256') {
  throw new Error('Algoritmo de assinatura inválido');
}

// 5. Obter o secret para verificar a assinatura (informações de como conseguir essa chave estão na sessão anterior Obtenção da chave Secret)
const secret = 'your-secret-key';

// 6. Obter o valor da mensagem
const message = `digest: ${headers.digest}\nhost: ${headers.host}\n`;

// 7. Gerar a signature esperada usando HMAC-SHA256
const expectedSignature = crypto.createHmac('sha256', secret)
  .update(message + sigInput.created + sigInput.nonce + sigParams)
  .digest('hex');

// 8. Comparar as signatures para verificar a autenticidade da mensagem
if (expectedSignature !== sigVal) {
  throw new Error('Assinatura inválida');
}

console.log('Mensagem autenticada com sucesso!');