Вебхуки: подписанные payload и повторные попытки
Вы только что интегрировали вебхук платёжного провайдера для получения обновлений о транзакциях. В тестах всё работает, но в продакшене вы замечаете пропущенные события при пиковых нагрузках или дублирующиеся списания, когда провайдер повторяет запрос. Вебхуки просты по концепции, но коварны на практике: они пересекают сетевые границы, могут задерживаться, дублироваться или подделываться. В этой статье объясняется, как построить надёжных потребителей и отправителей вебхуков с использованием подписанных 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 минут). Временная метка должна быть частью подписанных данных.
Реализация надёжных повторов
Сетевые проблемы или временные ошибки сервера могут привести к сбою доставки вебхука. Надёжный отправитель повторяет неудачные доставки с экспоненциальной задержкой.
Стратегия повторов
- Экспоненциальная задержка: ждите дольше между каждой попыткой (например, 1с, 2с, 4с, 8с...).
- Максимум повторов: установите лимит (например, 5 попыток), чтобы избежать бесконечных циклов.
- Очередь недоставленных сообщений: после исчерпания повторов сохраните событие для ручной проверки.
- Идемпотентность: включите уникальный ID события, чтобы получатель мог дедуплицировать.
Пример: повтор с задержкой на 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
Лучшие практики для потребителей вебхуков
- Отвечайте быстро: подтвердите получение статусом 2xx до обработки. Ставьте работу в очередь асинхронно.
- Проверяйте подписи: всегда проверяйте подпись, прежде чем доверять payload.
- Обрабатывайте дубликаты: используйте ID события для обеспечения идемпотентной обработки.
- Логируйте всё: ведите логи полученных вебхуков для отладки.
Сравнение: вебхуки против опроса
| Аспект | Вебхуки | Опрос |
|---|---|---|
| Задержка | Почти реальное время | Зависит от интервала |
| Нагрузка на сервер | Низкая (только push) | Высокая (частые запросы) |
| Сложность | Выше (нужен эндпоинт, безопасность) | Ниже |
| Надёжность | Требует повторов | Повторы по своей природе |
FAQ
Что такое подписанный payload вебхука?
Подписанный payload включает криптографическую подпись (обычно HMAC), которая позволяет получателю проверить подлинность и целостность запроса.
Сколько раз следует повторять неудачный вебхук?
Обычная практика — 3–5 повторов с экспоненциальной задержкой, но это зависит от вашего SLA и критичности события.
Можно ли использовать вебхуки без HTTPS?
Нет, всегда используйте HTTPS, чтобы защитить payload и подпись от перехвата. Простой HTTP раскрывает конфиденциальные данные.
При отладке payload вебхуков вам может понадобиться быстро отформатировать JSON. Попробуйте наш JSON Formatter, чтобы красиво отформатировать и проверить JSON-ответы.