Из-за временных ограничений на территории РФ наблюдаются проблемы с оплатой. Если платёж не проходит, оставьте запрос в службу поддержки.Служба поддержки работает 24/7 — мы всегда на связи по вопросам хостинга и серверов.Открыт прием заявок на аренду выделенных серверов и размещение оборудования в дата-центре.Напоминаем: рекомендуем включить резервное копирование для дополнительной защиты данных.Доступна новая линейка VPS/VDS с NVMe-дисками и увеличенной производительностью.Технические работы на части серверов завершены. Все сервисы работают в штатном режиме.
Статья5 мин чтенияПросмотры2

Подпись webhook не сходится: проверьте исходные байты JSON

Два JSON с одинаковыми данными могут иметь разные HMAC-подписи. Показываем проверенный пример с пробелами и границы проверки подлинности входящего уведомления.

Комментарии 0

Закрытый конверт с целой фиолетовой печатью и жёлтой нитью: сохранность исходного сообщения
В этой статье

Webhook приходит от ожидаемого сервиса, данные выглядят правильно, а подпись не сходится. Разработчик выводит JSON, сравнивает поля и не находит разницы. Причина может находиться между получением запроса и проверкой: приложение разобрало тело, затем собрало JSON заново. Значения сохранились, исходные байты — нет.

Для схемы, которая подписывает исходное тело запроса, проверять нужно именно его. Сначала сохраните доступ к исходным байтам предусмотренным способом своего фреймворка, затем проверьте подпись по контракту поставщика. Разбор данных для бизнес-логики не должен подменять проверяемое сообщение его новой сериализацией.

Одинаковые данные не означают одинаковое сообщение

Два учебных тела содержат один идентификатор заказа и одинаковый признак оплаты:

{"order_id":42,"paid":true}

{"order_id": 42, "paid": true}

Для JSON это одинаковые значения полей. Во втором теле добавлены пробелы. В локальной проверке Python разбор обоих тел дал равные объекты, а HMAC-SHA256 с одним учебным ключом — разные результаты. Подпись первого тела прошла проверку на исходных байтах и не прошла на втором варианте. Это небольшой воспроизводимый тест свойства байтов, не испытание обработчика конкретного магазина.

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

Что именно проверяет HMAC

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

Для конкретного примера можно свериться с документацией GitHub: рекомендуемая подпись webhook передаётся в заголовке X-Hub-Signature-256 и использует HMAC-SHA256. Проверяют исходное тело; документация отдельно предупреждает об изменениях полезной нагрузки и заголовков посредниками. Это контракт GitHub, его название заголовка нельзя автоматически переносить на платёжный или логистический сервис.

У другого поставщика в подписываемую строку могут входить время, путь запроса или другие элементы. Сначала выясняют состав сообщения, кодировку, алгоритм и формат подписи. Затем используют поддерживаемую библиотеку или официальный SDK. Угадывание по длине строки и подбор алгоритма до первого совпадения не заменяют контракт.

Для сравнения секретно-зависимых значений применяют предусмотренную криптографической библиотекой функцию, например hmac.compare_digest в Python. Она избегает раннего завершения сравнения в зависимости от содержимого. Типы и формат входа всё равно нужно проверять по документации; название функции не делает весь обработчик автоматически защищённым.

Как найти место, где тело изменилось

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

Не выводите рабочий секрет в журнал и не копируйте туда полные уведомления с данными покупателей ради диагностики. Для локального воспроизведения достаточно искусственного тела и отдельного тестового ключа. Если нужна проверка рабочего события, используйте согласованный защищённый процесс, а не публичный конвертер подписей.

В приёмке нужны как минимум исходное тело с верной подписью, изменённое тело со старой подписью, отсутствующая подпись и подпись другого тестового ключа. Для схемы подписания исходных байтов отдельно изменяют только пробел: отказ в этом случае ожидаем и показывает, что проверяется сообщение, а не сходство объектов.

Верная подпись не отменяет остальные проверки

Одна и та же корректная подпись может сопровождать повторную доставку неизменённого сообщения. Поэтому подлинность и обработка повторов — разные задачи. Сервис должен распознавать повтор события предусмотренным контрактом способом и не выполнять бизнес-действие ещё раз. У GitHub для отслеживания доставок есть отдельный идентификатор; правила другого отправителя проверяют отдельно.

После проверки подлинности остаются тип события, связь с нужным объектом, допустимость перехода состояния и уже выполненные действия. Для уведомления об оплате важно не только доверять источнику, но и корректно связать событие с заказом. Подписанный запрос не даёт разрешения применять любые переданные данные к любому объекту.

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

Обсуждение 0

Делись опытом и задавай вопросы. Комментарии без ссылок появляются после проверки редактором.

Пока никто не написал. Начни обсуждение.