Вебхуки: подписанные payload и повторные попытки

Backend2026-10-27TryQuickToolBox

Вы только что интегрировали вебхук платёжного провайдера для получения обновлений о транзакциях. В тестах всё работает, но в продакшене вы замечаете пропущенные события при пиковых нагрузках или дублирующиеся списания, когда провайдер повторяет запрос. Вебхуки просты по концепции, но коварны на практике: они пересекают сетевые границы, могут задерживаться, дублироваться или подделываться. В этой статье объясняется, как построить надёжных потребителей и отправителей вебхуков с использованием подписанных payload и продуманных стратегий повторов.

Что такое вебхуки?

Вебхуки — это определяемые пользователем HTTP-колбэки, запускаемые событиями. Когда что-то происходит в исходной системе (например, новый заказ), она отправляет HTTP POST-запрос на указанный вами URL. В отличие от опроса (polling), вебхуки передают данные почти в реальном времени, снижая задержку и нагрузку на сервер.

Однако вебхуки создают проблемы: нужно убедиться, что запрос действительно пришёл от ожидаемого отправителя, корректно обрабатывать сбои и избегать повторной обработки.

Защита вебхуков с помощью подписанных payload

Без проверки любой может отправлять поддельные запросы на ваш эндпоинт вебхука. Подписанные payload решают эту проблему, включая криптографическую подпись, которую вы можете проверить.

Как работают HMAC-подписи

Отправитель вычисляет код аутентификации сообщения на основе хеша (HMAC), используя общий секрет и тело запроса. Подпись отправляется в заголовке (например, X-Signature). Вы пересчитываете HMAC на своей стороне и сравниваете.

// Пример на Node.js: проверка подписи вебхука
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Всегда используйте функцию сравнения с постоянным временем, например timingSafeEqual, чтобы предотвратить атаки по времени.

Включите временную метку

Чтобы предотвратить атаки повторного воспроизведения, включите временную метку в подписанный payload и отклоняйте запросы старше нескольких минут (например, 5 минут). Временная метка должна быть частью подписанных данных.

Реализация надёжных повторов

Сетевые проблемы или временные ошибки сервера могут привести к сбою доставки вебхука. Надёжный отправитель повторяет неудачные доставки с экспоненциальной задержкой.

Стратегия повторов

Пример: повтор с задержкой на Python

import time
import requests
from requests.exceptions import RequestException

def send_webhook(url, payload, max_retries=5):
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=payload, timeout=5)
            if response.status_code < 500:
                return True  # успех или клиентская ошибка (без повтора)
        except RequestException:
            pass
        time.sleep(2 ** attempt)  # экспоненциальная задержка
    return False

Лучшие практики для потребителей вебхуков

Сравнение: вебхуки против опроса

АспектВебхукиОпрос
ЗадержкаПочти реальное времяЗависит от интервала
Нагрузка на серверНизкая (только push)Высокая (частые запросы)
СложностьВыше (нужен эндпоинт, безопасность)Ниже
НадёжностьТребует повторовПовторы по своей природе

FAQ

Что такое подписанный payload вебхука?

Подписанный payload включает криптографическую подпись (обычно HMAC), которая позволяет получателю проверить подлинность и целостность запроса.

Сколько раз следует повторять неудачный вебхук?

Обычная практика — 3–5 повторов с экспоненциальной задержкой, но это зависит от вашего SLA и критичности события.

Можно ли использовать вебхуки без HTTPS?

Нет, всегда используйте HTTPS, чтобы защитить payload и подпись от перехвата. Простой HTTP раскрывает конфиденциальные данные.

При отладке payload вебхуков вам может понадобиться быстро отформатировать JSON. Попробуйте наш JSON Formatter, чтобы красиво отформатировать и проверить JSON-ответы.