· 6 мин чтения
Вебхуки, которым можно верить: HMAC, ретраи и идемпотентность
Достоверность вебхука важнее его скорости. Как мы подписываем доставки, почему лесенка ретраев — 1м→12ч и что должен делать ваш обработчик, чтобы быть скучным и корректным.
В платёжной инфраструктуре вебхук, который лжёт, хуже вебхука, который не пришёл. Если ваш fulfillment доверяет неаутентифицированному POST, любой, кто дотянется до вашего endpoint'а, отгружает бесплатный VPS. В этом посте — три механизма, которые делают вебхуки ZeroKYC Pay безопасными для автоматизации.
1. Подписи: HMAC-SHA256 с временной меткой
Каждая доставка несёт X-ZKP-Signature и X-ZKP-Timestamp. Подпись — это HMAC-SHA256(secret, timestamp + "." + raw_body) секретом endpoint'а. Две детали критичны:
- Сырое тело. Подпись покрывает байты, а не смысл. Парсите JSON только после проверки, иначе пересериализация фреймворком сломает легитимные доставки.
- Временное окно. Подписанные запросы валидны 5 минут. Без окна злоумышленник, однажды перехвативший легитимный вебхук, мог бы реплеить его вечно; с окном реплеи тихо умирают.
Проверяйте в constant-time (timingSafeEqual, hash_equals, compare_digest) — иначе само сравнение становится side channel'ом.
2. Ретраи: честность про интернет
У endpoint'ов бывают деплои, рестарты и инциденты в два часа ночи. Считать одну неудачную доставку потерянными деньгами — ложь про поведение сетей, поэтому доставки ретраятся по лесенке: 1м → 5м → 30м → 2ч → 12ч, затем переходят в failed с кнопкой ручного retry в кабинете.
Обратная сторона — семантика at-least-once: одно событие может прийти дважды. Поэтому каждое событие несёт глобально уникальный id: сохраняйте, дедуплицируйте по нему — и двусмысленность доставки исчезает.
контракт доставки
успех → любой 2xx за секунды
ретраи → 1м, 5м, 30м, 2ч, 12ч, затем failed + ручной retry
порядок → по событию, ретраи могут идти вперемешку с новыми
истина → GET /v1/invoices/{id} важнее любого payload3. Rescan: последнее слово за цепочкой
Вебхуки — подсказки; гроссбух — цепочка. Rescan-задача перепроверяет каждый pending и detecting инвойс каждые 10 минут, поэтому пропущенный вотчером блок самолечится, и подтверждение приходит с опозданием — но приходит. Для мерчантов это одно правило: реагируйте на payment.confirmed, payment.detected используйте только для UX, а сомневаясь — спрашивайте API.
Скучность — это фича
Обработчик вебхуков, который проверяет подпись, следит за окном, дедуплицирует по event id и считает API источником истины, скучен — и скучные обработчики — это то, что нужно при обработке денег. Полный контракт с copy-paste-примерами для Node, PHP и Python — в справочнике вебхуков и гайде по проверке HMAC.