Autenticação de Webhooks
Todos os webhooks enviados pela API do Pagou, incluindo eventos de boletos (ex.: charge.created, charge.paid) e Pix (ex.: qrcode.completed, qrcode.refunded), incluem os headers X-Pagou-Signature e X-Pagou-Timestamp para verificar a autenticidade e integridade das notificações. Esta seção detalha como validar esses headers, incluindo o processo de verificação da assinatura HMAC-SHA256 e do timestamp, exemplos de código em Python e JavaScript, e boas práticas para segurança.
Visão Geral Técnica
Os webhooks da API do Pagou são enviados como requisições HTTP POST com corpo JSON para o notification_url configurado (ex.: https://your-webhook.com/notifications). Cada webhook inclui dois headers de autenticação:
X-Pagou-Signature: Assinatura HMAC-SHA256 do conteúdotimestamp + payload(onde payload é a string JSON bruta do corpo da requisição). A assinatura é gerada com a chave de API do cliente.X-Pagou-Timestamp: Timestamp em segundos desde o epoch (ex.: 1754332106 para 2025-08-04 18:28:26).
Validação dos Headers
Para garantir que o webhook é confiável, valide os headers X-Pagou-Signature e X-Pagou-Timestamp:
Obter a chave de API
Validar
X-Pagou-Signature:Extraia o
<hex>do headerX-Pagou-Signature.Concatene o valor de
X-Pagou-Timestampcom o payload JSON bruto (ex.:1754329142+{"name":"charge.created",...}).Calcule o HMAC-SHA256 do resultado usando a chave de API.
Compare o hash calculado com o
<hex>do header usando uma comparação resistente a ataques de tempo (ex.:crypto.timingSafeEqualem JavaScript,hmac.compare_digestem Python).
Rejeitar se inválido:
Retorne
401 Unauthorizedse a assinatura ou timestamp forem inválidos.Registre tentativas inválidas para monitoramento.
Nota: A validação dos headers é altamente recomendada para segurança, mas os webhooks são enviados mesmo que a validação não seja implementada.
Exemplos de Código
const crypto = require('crypto');
function verifySignature(payload, timestamp, signature, secret) {
const receivedDigest = signature;
const message = timestamp + payload;
const hmac = crypto.createHmac('sha256', secret);
hmac.update(message);
const computedDigest = hmac.digest('hex');
try {
const receivedBuffer = Buffer.from(receivedDigest, 'hex');
const computedBuffer = Buffer.from(computedDigest, 'hex');
if (receivedBuffer.length !== computedBuffer.length) {
return false;
}
return crypto.timingSafeEqual(receivedBuffer, computedBuffer);
} catch (e) {
return false;
}
}
// Example usage:
const payload = '{"name":"charge.created","data":{"id":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","transaction_id":"0","client_code":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","payload":{"transaction_id":"123","bank_emissor":"bradesco","bank_number":"137","bank_agency":"0001","bank_account":"12345678","bar_code":"123456789098765434321","line":"1234323465654758868986","bank_assignor":"Celcoin"}}}';
const timestamp = '1754329886'; // From X-Pagou-Timestamp header
const signature = 'ff502eeda47ceb3a6c0dc32a34d9503f32224f6fd8c9ad30a25c0f7cf0ca358c'; // From X-Pagou-Signature header
const apiKey = '07ab896a-d830-418b-8c55-47874dc6760e'; // API Key
const isValid = verifySignature(payload, timestamp, signature, apiKey);
console.log('Signature valid:', isValid);Boas Práticas Técnicas
Segurança: Sempre valide
X-Pagou-SignatureeX-Pagou-Timestamppara garantir a origem e integridade do webhook.Comparação Segura: Use funções como
crypto.timingSafeEqual(JavaScript) ouhmac.compare_digest(Python) para evitar ataques de tempo.Prevenção de Replay Attacks: Rejeite webhooks com
X-Pagou-Timestampfora de ±5 minutos do horário atual.Monitoramento: Registre
X-Pagou-Timestamp,X-Pagou-Signature, e resultados da validação em logs para auditoria.HTTPS: Use um certificado SSL válido para o
notification_url.
import hmac
import hashlib
def verify_signature(payload, timestamp, signature, secret):
message = timestamp + payload
computed_digest = hmac.new(
key=secret.encode('utf-8'),
msg=message.encode('utf-8'),
digestmod=hashlib.sha256
).hexdigest()
return hmac.compare_digest(computed_digest, signature)
# Example usage:
payload = '{"name":"charge.created","data":{"id":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","transaction_id":"0","client_code":"7a86b3b7-779e-4e9f-af7d-bf2e512ddae1","payload":{"transaction_id":"123","bank_emissor":"bradesco","bank_number":"137","bank_agency":"0001","bank_account":"12345678","bar_code":"123456789098765434321","line":"1234323465654758868986","bank_assignor":"Celcoin"}}}'
timestamp = '1754329886' # From X-Pagou-Timestamp header
signature = 'ff502eeda47ceb3a6c0dc32a34d9503f32224f6fd8c9ad30a25c0f7cf0ca358c' # From X-Pagou-Signature header
api_key = '07ab896a-d830-418b-8c55-47874dc6760e' # API Key
is_valid = verify_signature(payload, timestamp, signature, api_key)
print('Signature valid:', is_valid)Boas Práticas Técnicas
Segurança: Sempre valide
X-Pagou-SignatureeX-Pagou-Timestamppara garantir a origem e integridade do webhook.Comparação Segura: Use funções como
crypto.timingSafeEqual(JavaScript) ouhmac.compare_digest(Python) para evitar ataques de tempo.Prevenção de Replay Attacks: Rejeite webhooks com
X-Pagou-Timestampfora de ±5 minutos do horário atual.Monitoramento: Registre X-Pagou-Timestamp, X-Pagou-Signature, e resultados da validação em logs para auditoria.
HTTPS: Use um certificado SSL válido para o notification_url.
Testes: Valide webhooks no ambiente sandbox (https://sandbox.api.pagou.com.br/v1) usando ferramentas como ngrok.
Last updated