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.
- Após o registro nos eventos, você receberá um magic-link.
- 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:
| Passo | Ação | Descrição |
|---|---|---|
| 1 | Capturar Headers | Obtenha os valores de digest, signature e signature-inputda requisição |
| 2 | Validar Algoritmo | Verifique se o campo alg no header signature-input é hmac-sha256 |
| 3 | Reconstruir o Input | Monte a string de verificação utilizando o digest, a @target-uri (seu endpoint) e os metadados (created e nonce) |
| 4 | Gerar Local HMAC | Gere uma assinatura local usando sua Secret Key sobre a string montada |
| 5 | Comparar | Compare 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!');
Updated about 1 month ago