Вебхуки: приём, подпись, повторы, идемпотентность
↑ 5.5 Интеграции со сторонними API: 1С, Битрикс24, FHIR · ← Предыдущая · → Следующая
Зачем это на собесе
Вопрос «как безопасно принять вебхук от платёжной системы» проверяет и безопасность, и надёжность.
Объяснение
Вебхук — HTTP-запрос от внешней системы о событии. Принимающая сторона — ваш публичный endpoint, значит он атакуем и должен быть надёжным.
| Требование | Как |
|---|---|
| Аутентичность | проверка HMAC-подписи заголовка по секрету (X-Signature) над сырым телом |
| Защита от replay | метка времени в подписи, окно 5 минут |
| Быстрый ответ | принять, положить в очередь/БД, вернуть 2xx за секунды; обработка асинхронно |
| Идемпотентность | дедупликация по event_id |
| Повторы отправителя | провайдер повторяет при не-2xx: обрабатывайте дубли |
| Порядок | события могут прийти не по порядку: сверяйтесь с версией/временем или перезапрашивайте состояние |
| Наблюдаемость | лог событий, метрики, DLQ |
app.MapPost("/webhooks/acme", async (HttpRequest req, IWebhookQueue queue, IOptions<AcmeOptions> o) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
var body = ms.ToArray();
var expected = Convert.ToHexString(HMACSHA256.HashData(Encoding.UTF8.GetBytes(o.Value.Secret), body));
if (!CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(expected.ToLower()),
Encoding.UTF8.GetBytes(req.Headers["X-Signature"].ToString())))
return Results.Unauthorized();
await queue.EnqueueAsync(body); // сохранить и подтвердить
return Results.Ok();
});Нюансы и подводные камни
- Подпись считается по байтам тела: не пересериализуйте JSON до проверки.
- Сравнение подписи — за постоянное время.
- Долгая обработка в обработчике → таймаут у отправителя → лавина повторов.
- Не доверяйте содержимому: после события запросите актуальное состояние через API.
- Ограничьте размер тела и IP-адреса отправителя, если провайдер их публикует.
Практика
- Реализуйте приём вебхука с проверкой HMAC и защитой от replay.
- Сымитируйте повторную доставку и убедитесь в идемпотентности.
- Настройте DLQ для событий, которые не удалось обработать.
Вопросы с ответами
Как проверить подлинность вебхука?
HMAC-подпись по секрету над сырым телом, сравнение за постоянное время и проверка метки времени.
Почему отвечать нужно быстро?
Иначе отправитель посчитает доставку неудачной и повторит; тяжёлую обработку выносят в фон.
Как справиться с дублями?
Идемпотентность по
event_id(таблица обработанных событий).