Autenticação de webhooks - Proteja seus endpoints
O finlight oferece vários métodos de autenticação para proteger suas entregas de webhook. Cada webhook inclui validação de assinatura por padrão, com camadas de autenticação adicionais opcionais para maior segurança.
O finlight suporta quatro métodos de autenticação que podem ser usados individualmente ou em combinação:
Nenhum
Sem autenticação adicional além da validação de assinatura padrão.
Quando usar:
- Ambientes de teste e desenvolvimento
- Endpoints internos atrás de redes seguras
- Quando a validação de assinatura fornece segurança suficiente
Observação: A validação de assinatura ainda é incluída em cada requisição de webhook, independentemente dessa configuração.
Cabeçalho X-Finlight-Key
Envia sua chave de API em um cabeçalho personalizado X-Finlight-Key com cada requisição de webhook.
Configuração:
- Forneça sua chave de API durante a configuração do webhook
- A chave será incluída no cabeçalho
X-Finlight-Key
Implementação: Seu endpoint deve validar o cabeçalho recebido:
const finlightKey = req.headers['x-finlight-key']
if (finlightKey !== 'your-expected-api-key') {
return res.status(401).send('Invalid API key')
}
Cabeçalhos enviados:
X-Finlight-Key: your-api-key-value
X-Webhook-Signature: sha256=signature
X-Webhook-Timestamp: 2024-01-15T10:30:00.000Z
Autenticação básica
Autenticação básica HTTP com credenciais de usuário/senha.
Configuração:
- Defina o usuário e a senha durante a configuração do webhook
- As credenciais são codificadas em base64 e enviadas no cabeçalho
Authorization
Implementação: Seu endpoint recebe a autenticação básica HTTP padrão:
const auth = req.headers.authorization
if (!auth || !auth.startsWith('Basic ')) {
return res.status(401).send('Missing Basic Auth')
}
const credentials = Buffer.from(auth.slice(6), 'base64').toString()
const [username, password] = credentials.split(':')
if (username !== 'expected-user' || password !== 'expected-pass') {
return res.status(401).send('Invalid credentials')
}
Cabeçalhos enviados:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
X-Webhook-Signature: sha256=signature
X-Webhook-Timestamp: 2024-01-15T10:30:00.000Z
Validação de assinatura
Segurança automática: Cada requisição de webhook inclui validação de assinatura, independentemente do método de autenticação escolhido.
Como funciona:
- O finlight gera uma marca de tempo ao enviar o webhook
- Cria uma mensagem concatenando:
timestamp + '.' + payload - Assina a mensagem usando HMAC-SHA256 com a chave secreta do seu webhook
- Envia tanto a assinatura quanto a marca de tempo nos cabeçalhos
Cabeçalhos incluídos:
X-Webhook-Signature: sha256=computed-signature
X-Webhook-Timestamp: 2024-01-15T10:30:00.000Z
Algoritmo de assinatura:
message = timestamp + '.' + raw_request_body
signature = HMAC-SHA256(message, webhook_secret)
Quando nenhum cabeçalho X-Webhook-Timestamp está presente, a mensagem é apenas o corpo bruto. Compare o resultado em tempo constante e rejeite as entregas cuja marca de tempo tenha mais de cinco minutos.
O corpo deve ser os bytes brutos da requisição, sem processamento. Qualquer middleware que decodifique e recodifique o JSON antes de você lê-lo altera a sequência de bytes e invalida a assinatura — essa é a causa mais comum de falhas de verificação. Leia o corpo como uma string ou buffer bruto, verifique-o e só então faça o parse.
Verificação com um cliente oficial
Cada biblioteca cliente inclui um helper que faz toda a verificação por você: ele aceita o prefixo sha256= na assinatura, compara em tempo constante, aplica a janela de repetição de cinco minutos e retorna o artigo já processado. Ele lança uma exceção ou retorna um erro quando a verificação falha — responda sempre a isso com um 4xx e nunca processe o payload.
Verificar um webhook
import express from 'express'
import { WebhookService } from 'finlight-client'
const app = express()
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
try {
const article = WebhookService.constructEvent(
req.body.toString(),
req.headers['x-webhook-signature'] as string,
process.env.WEBHOOK_SECRET!,
req.headers['x-webhook-timestamp'] as string,
)
console.log('New article:', article.title)
res.sendStatus(200)
} catch (err) {
console.error('Webhook verification failed:', err)
res.sendStatus(400)
}
})
Melhores práticas de segurança
Validação de marca de tempo
Os helpers constructEvent acima já aplicam uma janela de repetição de cinco minutos, então isso só é necessário se você verificar as assinaturas manualmente:
function isTimestampValid(timestamp, toleranceSeconds = 300) {
const now = Date.now()
const requestTime = new Date(timestamp).getTime()
const difference = Math.abs(now - requestTime) / 1000
return difference <= toleranceSeconds
}
Armazenamento seguro de credenciais
- Variáveis de ambiente: Armazene todos os segredos em variáveis de ambiente
- Gestão de segredos: Use AWS Secrets Manager, HashiCorp Vault ou similar
- Nunca codifique diretamente: Nunca faça commit de segredos no controle de versão
- Rotação regular: Atualize os segredos de webhook periodicamente
Para orientação sobre a configuração de webhooks, consulte a documentação principal de webhooks. Para testes abrangentes, consulte o guia de testes de webhooks.