Webhooks: подписанные payload и повторные попытки

Backend2026-10-24TryQuickToolBox

Вы создали API, и теперь нужно уведомлять другие сервисы о событиях. Вы настроили endpoint для webhook, но быстро поняли, что надёжная доставка HTTP-запросов сложнее, чем кажется. Сетевые сбои, злоумышленники и дублирующиеся события могут вызвать хаос. Это руководство объясняет, как реализовать webhooks с подписанными payload и повторными попытками, чтобы построить надёжную интеграцию.

Что такое Webhooks?

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

Например, платёжный процессор может отправить webhook в ваше приложение, когда платёж успешно проведён. Ваше приложение может сразу обновить статус заказа.

Зачем подписывать payload webhook?

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

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

Как генерировать и проверять подписи

Большинство реализаций используют HMAC-SHA256. Вот простой пример на Python:

import hmac
import hashlib
import json

def generate_signature(payload, secret):
    body = json.dumps(payload, separators=(',', ':')).encode('utf-8')
    signature = hmac.new(secret.encode('utf-8'), body, hashlib.sha256).hexdigest()
    return signature

def verify_signature(payload, signature, secret):
    expected = generate_signature(payload, secret)
    return hmac.compare_digest(expected, signature)

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

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

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

Стратегия повторных попыток

Распространённый подход — повторять с увеличивающимися задержками: 1 минута, 5 минут, 30 минут, 2 часа и т.д. Остановитесь после максимального числа попыток (например, 10) или общего временного окна (например, 24 часа).

Повторяйте только при определённых условиях: сетевые ошибки, ответы 5xx или 429 (Too Many Requests). Не повторяйте при ошибках 4xx (кроме 429), потому что они указывают на ошибку клиента, которая не исправится повторной попыткой.

Пример логики повторных попыток

Вот упрощённый механизм повторных попыток на Python с использованием библиотеки requests:

import requests
import time
from requests.exceptions import RequestException

def send_webhook(url, payload, secret, max_retries=5):
    headers = {'Content-Type': 'application/json'}
    signature = generate_signature(payload, secret)
    headers['X-Signature'] = signature
    
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=payload, headers=headers, timeout=10)
            if response.status_code < 500 and response.status_code != 429:
                return response.status_code
        except RequestException:
            pass
        
        # Экспоненциальная задержка с джиттером
        delay = (2 ** attempt) + (random.random() * 0.1)
        time.sleep(delay)
    
    return None  # Не удалось после повторных попыток

В production вы бы сохраняли неудачные попытки в очередь и обрабатывали их асинхронно. Инструменты вроде Celery или облачные очереди (AWS SQS, Google Cloud Tasks) могут помочь.

Лучшие практики безопасности webhook

Обработка дубликатов и идемпотентность

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

В качестве альтернативы проектируйте обработчики событий идемпотентными. Например, обновление записи одними и теми же данными несколько раз должно иметь тот же эффект, что и однократное.

Тестирование webhooks

Используйте инструменты вроде ngrok, чтобы открыть локальный сервер и протестировать доставку webhook. Имитируйте сбои, возвращая коды ошибок, и проверяйте, что повторные попытки происходят как ожидалось.

FAQ

Что такое подписанный payload webhook?

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

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

Зависит от ваших потребностей в надёжности. Распространённая практика — 5-10 повторных попыток с экспоненциальной задержкой в течение 24 часов. Всегда позволяйте подписчикам вручную инициировать повторную попытку.

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

Можно, но это рискованно. Без подписи любой может отправлять поддельные события. Всегда подписывайте webhooks в production, чтобы предотвратить мошенничество.

Готовы протестировать свои payload webhook? Используйте наш JSON Formatter, чтобы проверить и отформатировать JSON payload перед отправкой.