Назад в блог
Заказное ПО

Что такое вебхук и как использовать его безопасно

Что такое вебхук и чем он отличается от API? Это когда другая система сама вызывает вас, как только что-то произошло. Как вебхуки применяются в интеграциях с платежами, доставкой и маркетплейсами, как проверять подпись и переживать повторные доставки: с примером на Next.js.

WebhookAPIEntegrasyonÖzel Yazılım

Короткий ответ на вопрос «что такое вебхук»: когда в одной системе происходит событие (списан платёж, доставлена посылка, отменён заказ), эта система сама отправляет HTTP-запрос на адрес, который вы указали, без вашего обращения. В обычном API вопрос задаёте вы; с вебхуком новость приходит к вам. Разница кажется небольшой, но она меняет стоимость, задержку и поверхность атаки интеграции от начала до конца. В этой статье мы объясняем, как работают вебхуки, где они применяются, что обязан делать правильно построенный приёмник и что нужно спроектировать заранее, если ваша собственная система будет отправлять вебхуки другим. По этим правилам мы строим интеграционный слой в проектах заказного ПО.

Вебхук и API: в чём разница?

Оба работают поверх HTTP; разница в направлении и моменте. С API клиент — вы: вы спрашиваете «оплачен ли этот заказ?», а другая сторона сообщает текущее состояние. Чтобы узнать ответ, либо пользователь нажимает кнопку, либо ваша система задаёт тот же вопрос снова через заданный интервал; это называется опросом (polling). С вебхуком вы передаёте адрес («сообщи сюда, когда придёт платёж»), и другая система при наступлении события отправляет туда POST-запрос. Вы не спрашиваете, вы слушаете. Общие понятия мы разобрали в статье что такое API-интеграция; здесь речь только о вебхуках.

Опрос и вебхуки не соперники, а дополнение друг друга. Если события частые и важна мгновенная реакция (подтверждение оплаты, входящее сообщение), вебхук — правильный инструмент: система, которая каждые пять секунд спрашивает «уже пришло?», тратит запросы впустую и всё равно опаздывает в среднем на две с половиной секунды. Если события редкие, а другая сторона не предлагает вебхуков, опрос — единственный вариант; так обстоит дело с большинством бухгалтерских программ, о чём мы отдельно писали в статье об интеграции с бухгалтерской программой.

Как работает вебхук: по шагам

  • Вы открываете в своей системе публичный HTTPS-адрес, например /api/webhooks/payment. Он принимает только POST и не ожидает пользовательской сессии.
  • Вы регистрируете этот адрес в панели провайдера или через его API; провайдер выдаёт вам секретный ключ.
  • Когда событие происходит, провайдер отправляет тип и данные события в формате JSON на этот адрес, а в заголовке запроса передаёт подпись, вычисленную с помощью секрета.
  • Ваш сервер проверяет подпись, сохраняет событие, быстро возвращает провайдеру 200 и выполняет основную работу (пометить заказ оплаченным, отправить письмо) отдельно.
  • Если сервер не вернул 200 или вернул слишком поздно, провайдер повторно отправляет то же событие с нарастающими интервалами; поэтому одно событие может прийти несколько раз.

Где применяются вебхуки?

В корпоративных проектах, с которыми мы работаем, вебхуки чаще всего встречаются в интеграциях с платежами, доставкой, маркетплейсами и мессенджерами. В платёжной интеграции заказ помечает оплаченным не экран успеха, который видит пользователь, а проверенный вебхук от провайдера. В интеграции с доставкой перевозчик сообщает о каждой смене статуса (в доставке, доставлено, возврат), и страница отслеживания обновляется без запросов. В интеграции с маркетплейсом так приходят новые заказы и отмены, а через WhatsApp Business API — входящие сообщения и отчёты о доставке. Общее одно: событие происходит вне вашей системы, в чужой, и вы не управляете его временем.

Первое правило вебхуков: вебхук — это уведомление, а не источник истины. Действительно ли списаны деньги, действительно ли отменён заказ? При сомнении проверяйте через API провайдера по идентификатору события. Хороший приёмник доверяет вебхукам, но никогда не зависит только от них.

Безопасность вебхуков: проверка подписи и повторные доставки

Адрес вебхука по определению публичен; любой, кто его знает, может отправить поддельный запрос «платёж получен». Поэтому каждый провайдер подписывает запрос секретом, а вы заново вычисляете подпись по сырому телу и сравниваете. Две классические ошибки: сначала разобрать тело в JSON и подписать результат (пробелы и порядок полей меняются, подпись никогда не совпадёт) и сравнивать обычным равенством (уязвимо к атакам по времени). Вторая большая тема — повторные доставки: если провайдер не получил 200, он отправляет то же событие снова; если ваша бизнес-логика не уникальна по идентификатору события, остаток спишется дважды или по одному заказу уйдут два письма. Обработчик маршрута Next.js ниже применяет все три правила: сравнение подписи за постоянное время по сырому телу, уникальность по идентификатору события и вынос тяжёлой работы в очередь, чтобы провайдер быстро получил ответ.

// app/api/webhooks/payment/route.ts
import { createHmac, timingSafeEqual } from 'node:crypto';
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
  // Подпись считается по СЫРОМУ телу; JSON.parse не делаем заранее.
  const raw = await req.text();
  const received = req.headers.get('x-signature') ?? '';
  const expected = createHmac('sha256', process.env.PAYMENT_WEBHOOK_SECRET!)
    .update(raw)
    .digest('hex');

  // Сравнение за постоянное время: защита от атак по времени.
  if (
    received.length !== expected.length ||
    !timingSafeEqual(Buffer.from(received), Buffer.from(expected))
  ) {
    return new NextResponse('invalid signature', { status: 401 });
  }

  const event = JSON.parse(raw) as { id: string; type: string; data: unknown };

  // Идемпотентность: если то же событие пришло снова, логика не повторяется.
  const isNew = await db.webhookEvents.insertIfAbsent({
    id: event.id,
    type: event.type,
    payload: raw,
    receivedAt: new Date(),
  });
  if (!isNew) return NextResponse.json({ ok: true, duplicate: true });

  // Тяжёлая работа (остатки, письма, счета) — в очередь; провайдеру быстрый 200.
  await queue.enqueue('process-webhook', { eventId: event.id });
  return NextResponse.json({ ok: true });
}

Хранить сырое событие — не пустая аккуратность. Если задача в очереди упала, запись можно обработать заново; если вы спорите с провайдером о том, было ли событие доставлено, у вас есть доказательство; а когда вы начинаете поддерживать новое поле, можно перечитать прошлые события. Настройку очереди и отслеживания ошибок мы описали в статье о мониторинге ошибок и логировании; приёмник вебхуков — лучший пример «сигнала тишины» из той статьи, потому что переставший приходить вебхук не создаёт ошибку, он просто замолкает.

Что, если вебхук так и не пришёл? Повторы и досылка

Если ваш сервер недоступен час, события этого часа не теряются, но как долго они будут повторяться, зависит от провайдера: кто-то повторяет несколько часов, кто-то три дня, кто-то после пяти неудач полностью отключает адрес. Поэтому с первого дня настраиваются две вещи. Первая: политика повторов провайдера и условие отключения адреса записываются в документ передачи. Вторая: периодическая сверка: раз в ночь у провайдера запрашивается список событий или операций за последние 24 часа, сравнивается с вашими записями, и пропуски обрабатываются. Вебхук — мгновенный путь, сверка — ремень безопасности. Интеграция без обоих однажды тихо потеряет данные.

Если ваша система будет отправлять вебхуки

Если вы строите дилерский портал, SaaS-продукт или корпоративную панель, однажды клиент скажет: «уведомляйте нашу систему, когда создаётся заказ». В этот день вы должны обеспечить всё, чего ожидали от приёмника: события несут уникальный идентификатор и метку времени; каждый запрос подписан секретом, индивидуальным для клиента; отправка идёт из очереди, а неудачные доставки повторяются с нарастающими интервалами (1 мин, 5 мин, 30 мин, 2 часа); в панели клиента есть журнал доставок и кнопка «отправить снова». Чаще всего упускают версионирование событий: добавить новое поле в тело можно, но переименовать или изменить смысл существующего поля — значит сломать интеграции клиентов; схема события — часть договора. О проектировании открытого API читайте в статье REST или GraphQL, об общей поверхности атаки — в статье о безопасности сайта.

Пять ошибок, которые ломают проект с вебхуками

  • Не проверять подпись или «добавим потом»: адрес публичен, он работает с подписью с первого дня.
  • Делать основную работу внутри запроса вебхука: когда почтовый сервер замедляется, провайдер получает таймаут, отправляет событие снова, и работа выполняется дважды.
  • Не хранить идентификатор события: повторную доставку не отличить, один заказ обрабатывается дважды.
  • Направлять боевой вебхук провайдера в тестовую среду: тестовые и боевые ключи раздельны, адреса тоже должны быть раздельными.
  • Считать вебхук единственным источником истины: без сверки сбой замечают только тогда, когда звонит клиент.

Вывод

Вебхук — самый быстрый и дешёвый способ связать две системы; проблемы создаёт не вебхук, а недостроенный приёмник. Проверка подписи, уникальность по идентификатору события, очередь и сверка: когда эти четыре части на месте, ваша интеграция с платежами, доставкой, маркетплейсом или мессенджером годами работает тихо. Если вы планируете проект с интеграционным слоем, посмотрите нашу услугу разработки заказного ПО или запросите расчёт; на этапе исследования мы вместе определим, какие провайдеры предлагают вебхуки, а где придётся обойтись опросом и сверкой.

Let's Build Your Project

Get a free consultation for your website, mobile app, or corporate software project.

Get a Free QuoteExplore our Custom Software service