Вебхуки: подписанные данные и стратегии повтора
Вы только что интегрировали платежный шлюз или сервис CI/CD, и теперь вам нужно получать события в реальном времени. Вы настроили конечную точку, но вскоре сталкиваетесь с двумя критическими вопросами: как убедиться, что запрос действительно пришел от сервиса? И что произойдет, если ваш сервер недоступен, когда событие срабатывает? Эта статья отвечает на оба вопроса, объясняя подписанные данные и стратегии повтора — основу надежных вебхуков.
Что такое вебхуки?
Вебхуки — это определяемые пользователем HTTP-обратные вызовы. Когда в исходной системе происходит событие (например, новый коммит, успешный платеж), она отправляет HTTP POST-запрос на указанный вами URL. В отличие от опроса, вебхуки передают данные почти в реальном времени, снижая задержку и нагрузку на сервер. Однако эта модель push-уведомлений создает проблемы: проверка подлинности и обработка сбоев доставки.
Почему важны подписанные данные
Любой может отправить HTTP-запрос на вашу конечную точку. Без проверки злоумышленники могут подделать события, что приведет к несанкционированным действиям. Подписанные данные решают эту проблему, включая криптографическую подпись, вычисленную по телу запроса с использованием общего секрета. Получатель пересчитывает подпись и сравнивает ее, гарантируя, что данные не изменены и исходят от ожидаемого отправителя.
Как работают подписи HMAC
Большинство сервисов используют HMAC-SHA256. Отправитель создает подпись, хешируя данные с помощью секретного ключа, и включает ее в заголовок (например, X-Signature). Получатель делает то же самое и сравнивает с помощью функции постоянного времени для предотвращения атак по времени.
Пошагово: проверка подписанных данных
- Извлеките подпись из заголовка (например,
X-Signature). - Получите исходное тело запроса в виде строки или буфера — не анализируйте его заранее, так как изменения форматирования нарушают подпись.
- Вычислите ожидаемую подпись с помощью HMAC-SHA256 с вашим секретным ключом.
- Сравните подписи с помощью функции сравнения постоянного времени.
- Отклоните запрос с HTTP 401, если они не совпадают.
Вот пример на Node.js с использованием Express:
const crypto = require('crypto');
const express = require('express');
const app = express();
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-signature'];
const secret = process.env.WEBHOOK_SECRET;
const payload = req.body; // raw buffer
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
// Process the event
const event = JSON.parse(payload);
// ... handle event
res.status(200).send('OK');
});
Примечание: Всегда используйте исходное тело для проверки. Промежуточное ПО, анализирующее JSON, изменит данные, вызвав несоответствие подписи.
Разработка стратегии повтора
Даже с подписанными данными сетевые проблемы или простои сервера могут вызвать сбои доставки. Надежная стратегия повтора гарантирует, что события не будут потеряны. Ключевые соображения:
1. Быстрое подтверждение
Ответьте статусом 2xx, как только проверите подпись и поставите событие в очередь на обработку. Это предотвратит тайм-аут отправителя и ненужные повторные попытки.
2. Идемпотентность
Повторы могут доставить одно и то же событие несколько раз. Используйте ключ идемпотентности (часто включаемый в данные или заголовки) для дедупликации. Сохраняйте идентификаторы обработанных событий и игнорируйте дубликаты.
3. Экспоненциальная задержка с джиттером
Если ваша конечная точка возвращает ошибку (не 2xx), отправитель должен повторить попытку с увеличивающимися задержками. Экспоненциальная задержка (например, 1 с, 2 с, 4 с, 8 с) снижает нагрузку во время сбоев. Добавление случайного джиттера предотвращает проблему «стада».
Типичное расписание повторов:
| Попытка | Задержка |
|---|---|
| 1 | Немедленно |
| 2 | 1 минута |
| 3 | 5 минут |
| 4 | 30 минут |
| 5 | 2 часа |
4. Очередь недоставленных сообщений
После максимального числа повторов переместите событие в очередь недоставленных сообщений для ручной проверки. Это предотвращает бесконечные повторы и потерю данных.
5. Мониторинг и оповещения
Отслеживайте процент успешных доставок, задержку и причины сбоев. Настройте оповещения о всплесках сбоев, чтобы вовремя обнаруживать проблемы.
Распространенные ошибки и лучшие практики
- Всегда проверяйте подписи — никогда не доверяйте входящим данным слепо.
- Используйте HTTPS для защиты данных при передаче.
- Периодически меняйте секреты и поддерживайте несколько активных секретов во время ротации.
- Журналируйте события вебхуков (с редактированием конфиденциальных данных) для отладки.
- Тестируйте с образцами данных, используя инструменты, имитирующие доставку вебхуков.
Часто задаваемые вопросы
Что такое подписанные данные в вебхуках?
Подписанные данные включают криптографическую подпись (обычно HMAC), которая позволяет получателю проверить подлинность и целостность запроса.
Сколько раз следует повторять вебхук?
Фиксированного числа нет; распространенная практика — от 3 до 10 повторов с экспоненциальной задержкой. После этого события часто отправляются в очередь недоставленных сообщений.
Можно ли использовать вебхуки без подписей?
Это возможно, но крайне не рекомендуется. Без подписей ваша конечная точка уязвима для поддельных запросов и утечек данных.
Готовы протестировать данные вашего вебхука? Используйте наш JSON Formatter для быстрой проверки и валидации JSON-данных.