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

Backend2026-10-28TryQuickToolBox

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

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

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

Вебхуки обеспечивают связь между сервисами в реальном времени без постоянного опроса. Они широко используются платёжными шлюзами, инструментами CI/CD и SaaS-платформами.

Зачем защищать вебхуки?

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

Подписание payload с помощью HMAC

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

Пошагово: отправка подписанного вебхука

  1. Создайте payload (JSON).
  2. Вычислите HMAC-SHA256 от payload с использованием секрета.
  3. Включите hex-дайджест в заголовок, например, X-Signature: sha256=....
  4. Отправьте POST-запрос.
// Пример на Node.js с использованием crypto
const crypto = require('crypto');
const secret = 'your_shared_secret';
const payload = JSON.stringify({ event: 'payment.success', amount: 100 });
const signature = crypto.createHmac('sha256', secret).update(payload).digest('hex');
// Отправьте POST с заголовком X-Signature: sha256=signature

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

На стороне получателя извлеките заголовок подписи, вычислите HMAC от исходного тела запроса и сравните, используя сравнение с постоянным временем для предотвращения атак по времени.

// Пример на Express.js
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature'];
  const computed = crypto.createHmac('sha256', secret).update(req.rawBody).digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computed))) {
    return res.status(401).send('Invalid signature');
  }
  // Обработайте payload
  res.status(200).send('OK');
});

Примечание: убедитесь, что используете исходное тело, а не распарсенный JSON, так как парсинг может изменить payload.

Предотвращение атак повторного воспроизведения

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

Логика повторов для надёжной доставки

Конечные точки вебхуков могут быть недоступны или работать медленно. Реализуйте повторные попытки с экспоненциальной задержкой и джиттером. Установите максимальное количество повторов (например, 5) и таймаут для каждого запроса.

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

Пример расписания повторов: 1-й повтор через 5 с, 2-й через 30 с, 3-й через 2 мин, 4-й через 10 мин, 5-й через 1 ч.

Обработка сбоев

Если все повторы не удались, зарегистрируйте сбой и уведомите подписчика (например, по электронной почте или через панель управления). Предоставьте возможность ручной повторной отправки вебхуков.

Сравнение: подписанные payload vs. базовая аутентификация

Метод Безопасность Сложность Защита от повторов
HMAC подписанный payload Высокая Средняя Да (с временной меткой)
Базовая аутентификация Низкая Низкая Нет
API-ключ в заголовке Средняя Низкая Нет

Лучшие практики

Часто задаваемые вопросы

Как проверить подпись вебхука?

Вычислите HMAC от исходного тела запроса с использованием вашего секрета и сравните его с заголовком подписи, используя сравнение с постоянным временем.

Что делать, если вебхук не удался?

Реализуйте повторные попытки с экспоненциальной задержкой и джиттером. Если все повторы не удались, зарегистрируйте сбой и предоставьте возможность ручной повторной отправки.

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

Это не рекомендуется. Без подписи вы не можете проверить отправителя, что делает вашу систему уязвимой для подделки и атак повторного воспроизведения.

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