Перейти к содержимому
ZeroKYC Pay

· 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} важнее любого payload

3. Rescan: последнее слово за цепочкой

Вебхуки — подсказки; гроссбух — цепочка. Rescan-задача перепроверяет каждый pending и detecting инвойс каждые 10 минут, поэтому пропущенный вотчером блок самолечится, и подтверждение приходит с опозданием — но приходит. Для мерчантов это одно правило: реагируйте на payment.confirmed, payment.detected используйте только для UX, а сомневаясь — спрашивайте API.

Скучность — это фича

Обработчик вебхуков, который проверяет подпись, следит за окном, дедуплицирует по event id и считает API источником истины, скучен — и скучные обработчики — это то, что нужно при обработке денег. Полный контракт с copy-paste-примерами для Node, PHP и Python — в справочнике вебхуков и гайде по проверке HMAC.