Назад к руководствам
Команда Pulse2Pay10 января 2025 г.2 мин чтения

Безопасность Webhook: подписи, повторы и идемпотентность

Защитите вашу платёжную интеграцию с помощью HMAC подписей, защиты от replay-атак и идемпотентной обработки.

Webhooks — основа уведомлений о платежах в реальном времени. Это руководство объясняет, как защитить ваш webhook endpoint.

Понимание подписей Webhook

Каждый webhook от Pulse2Pay включает два заголовка безопасности:

ЗаголовокОписание

|-----------|----------|

X-Pulse2Pay-SignatureHMAC-SHA256 подпись запроса X-Pulse2Pay-TimestampUnix timestamp отправки (миллисекунды)

Проверка подписи

Важно: Подписи webhook используют другой формат, чем подписи API запросов!

// Подпись API (для ваших запросов к Pulse2Pay):

HMAC-SHA256(api_secret, timestamp + "." + method + "." + path + "." + body)

// Подпись Webhook (для запросов Pulse2Pay к вам):

HMAC-SHA256(webhook_secret, timestamp + "." + body)

Секрет webhook предоставляется при регистрации endpoint.

Пример реализации (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(req, webhookSecret) {

const signature = req.headers['x-pulse2pay-signature'];

const timestamp = req.headers['x-pulse2pay-timestamp'];

// Используйте сырое тело для точной проверки подписи

const body = req.rawBody || JSON.stringify(req.body);

// Проверка timestamp в пределах 5 минут (timestamp в миллисекундах)

const now = Date.now();

if (Math.abs(now - parseInt(timestamp)) > 300000) {

throw new Error('Timestamp устарел - возможная replay атака');

}

// Вычисление ожидаемой подписи (формат webhook: timestamp.body)

const payload = ${timestamp}.${body};

const expected = crypto

.createHmac('sha256', webhookSecret)

.update(payload)

.digest('hex');

if (!crypto.timingSafeEqual(

Buffer.from(signature),

Buffer.from(expected)

)) {

throw new Error('Неверная подпись');

}

return true;

}

Логика повторов

Pulse2Pay повторяет неудачные webhooks с экспоненциальной задержкой:

ПопыткаЗадержка

|---------|----------|

1Немедленно 21 секунда 35 секунд 430 секунд 51 минута 65 минут

После 5 неудачных попыток webhook будет помечен как failed.

Идемпотентная обработка

Ваш обработчик должен быть идемпотентным. Один webhook может быть доставлен несколько раз.

async function handlePaymentWebhook(payment) {

const existing = await db.getPayment(payment.id);

if (existing && existing.status === payment.status) {

return { success: true, duplicate: true };

}

await db.updatePayment(payment.id, {

status: payment.status,

tx_hash: payment.tx_hash,

processed_at: new Date()

});

return { success: true };

}

Связанные ресурсы

  • Приём USDT платежей
  • API Reference
  • #webhooks#безопасность#hmac#идемпотентность

    Готовы начать?

    Создайте аккаунт мерчанта и начните принимать криптоплатежи уже сегодня.