Не совпадает HMAC-подпись вебхука: как проверить raw body

Вебхук приходит, но проверка подписи не проходит. Порядок диагностики секрета, заголовка и исходных байтов запроса без отключения защиты.

Вебхук доходит до сайта, но обработчик отклоняет его с ошибкой подписи? Сначала проверьте три вещи: секрет именно этого endpoint, заголовок подписи и исходное тело запроса до разбора JSON. Успешное открытие сайта не подтверждает исправность этого обработчика.

HMAC связывает сообщение с общим секретом. Если провайдер подписывает исходные байты, одинаковые по смыслу JSON-документы могут иметь разные подписи: пробелы, порядок полей и перенос строки меняют входные данные. Отключать проверку ради восстановления доставки нельзя.

1. Отделите отказ подписи от ошибки доставки

Найдите одну неуспешную попытку в кабинете отправителя и соответствующий запрос в журнале приложения. Сопоставьте время с часовым поясом, маршрут, HTTP-код и внутренний идентификатор трассировки.

Если запрос не дошёл до обработчика, сначала разбирайте DNS, TLS, маршрутизацию или ограничения доступа. Если приложение зафиксировало именно отказ проверки подписи, переходите к входным данным проверки; один код 400 или 403 ещё не доказывает причину.

Не сохраняйте полный payload, секрет или заголовок подписи в общий журнал. Для первичной диагностики достаточно этапа отказа, длины тела и версии конфигурации без её значений.

2. Сверьте контракт конкретного провайдера

Запишите для разработчика короткую карточку проверки:

  • какое имя заголовка используется;
  • какой алгоритм и формат результата нужны: hex или Base64;
  • подписывается только тело или составная строка с дополнительными полями;
  • какой секрет назначен этому адресу и окружению;
  • предусмотрены ли версия подписи и проверка времени.

Например, GitHub передаёт HMAC-SHA256 в заголовке X-Hub-Signature-256 с префиксом sha256=. Сравнение выполняют функцией с постоянным временем, а не обычным оператором равенства. Это описано в документации проверки доставок GitHub.

Не переносите этот формат на другого отправителя. Секрет вебхука также не следует автоматически считать API-ключом: сверяйте назначение через штатное хранилище секретов, не выводя значение в консоль или переписку.

3. Найдите место, где изменилось тело

Проследите путь запроса: входной прокси → middleware приложения → обработчик подписи → JSON-парсер. Для схемы с подписью raw body проверяющий код должен получить неизменённое тело, а бизнес-обработчик — уже проверенные данные.

Показательный тест: {"ok":true} и { "ok": true } дают одинаковый объект после разбора JSON, но это разные последовательности байтов. Повторная сериализация объекта не восстанавливает исходный запрос.

Проверьте, не происходит ли до верификации:

  1. разбор JSON с последующей сборкой строки;
  2. удаление пробелов или завершающего переноса;
  3. изменение кодировки или экранирования Unicode;
  4. чтение потока другим компонентом без сохранения исходного тела.

Stripe отдельно описывает изменение тела фреймворками и различие секретов endpoint, созданного в кабинете, и доставки через CLI. Для Express порядок подключения JSON-middleware имеет значение. См. разбор ошибок подписи Stripe.

Для сравнения этапов используйте искусственный payload в тестовом окружении: сопоставьте длину и байты до и после middleware. Не копируйте боевые сообщения с персональными данными в публичные сервисы вычисления HMAC.

4. Разделите ошибки по воспроизводимости

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

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

Если контракт проверяет timestamp, отдельно сверяйте часы сервера и допустимый возраст сообщения. Старый сохранённый запрос может не пройти такую проверку даже с правильной подписью; расширять окно наугад нельзя.

5. Подтвердите исправление без побочных действий

Проведите проверку на изолированном стенде, где обработчик не создаёт реальные заказы и не отправляет письма:

  • корректная тестовая доставка проходит;
  • изменение одного байта тела приводит к отказу;
  • отсутствие подписи и неверный секрет приводят к отказу;
  • отклонённое сообщение не меняет бизнес-данные;
  • повтор принятого события не выполняет действие второй раз.

Подлинность сообщения и безопасность повторов — разные задачи. После успешной проверки подписи остаётся защитить состояние от дублей и запоздалых событий: этому посвящён материал о порядке обработки вебхуков.

Когда нужна помощь

Web-Puls помогает контролировать доступность сайта, но обычная внешняя HTTP-проверка не воспроизводит подписанную доставку провайдера. Для этого нужны тест обработчика и наблюдение за результатами приёма событий.

Если место изменения тела найти не удалось, отправьте заявку на диагностику: укажите провайдера, публичный адрес без секретных параметров, время ошибки, HTTP-код и недавние изменения. Команда поддержки оценит задачу и предложит формат работ; секреты, подписи и персональные payload в заявку не включайте.

Проверьте свой сайт прямо сейчас

Введите адрес сайта: Web-Puls покажет HTTP-код, время ответа и базовую диагностику. Для постоянного контроля можно подключить мониторинг.

Нужна помощь с диагностикой ошибки?

Опишите симптомы в короткой заявке: URL, код ответа, время появления и что менялось перед сбоем. Специалист поддержки оценит задачу и предложит формат работ.