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

Вебхук с корректной HMAC-подписью не обязательно безопасен: запрос могут повторить, доставить с задержкой или отправить на обработчик, который проверяет не те байты. Перед продакшеном нужно проверить не только вычисление подписи, но и весь путь запроса — от приёма тела до запуска бизнес-операции.
Сначала определите, что именно вы проверяете
У вебхуков нет единого формата подписи. Провайдер задаёт собственные заголовки, алгоритм, состав подписываемых данных и правила повторной доставки. Например, GitHub использует заголовок X-Hub-Signature-256 для HMAC-SHA-256 от тела запроса, а Stripe передаёт данные подписи в Stripe-Signature и включает временную метку. Не переносите схему одного сервиса на другой: сверяйтесь с актуальной документацией именно того провайдера и учитывайте версию его API, если она влияет на формат события.
Для вебхука, который вы принимаете, зафиксируйте в спецификации: какие байты подписаны, где передаётся подпись, как выбирается секрет, есть ли временная метка и идентификатор доставки, как провайдер повторяет запросы. Если хотя бы один пункт неизвестен, сначала уточните его у поставщика интеграции.
Термин. Повторная атака (replay attack) — повторная отправка ранее перехваченного корректного запроса. Подпись подтверждает, что запрос сформирован обладателем секрета, но сама по себе не доказывает, что этот запрос новый.
Чек-лист перед запуском
- Проверяйте исходное тело. Вычисляйте подпись по тем же байтам, которые подписывал отправитель, до разбора JSON. Повторная сериализация может поменять пробелы, порядок полей или экранирование и дать другое значение подписи. Проверка: тест с корректным запросом проходит, а изменение одного байта в теле приводит к отказу.
- Повторяйте алгоритм провайдера буквально. Уточните алгоритм, кодировку подписи, разделители и состав данных. Не угадывайте по названию заголовка. Проверка: тестовые векторы из документации провайдера дают ожидаемый результат, а запрос с подписью от другого тела не проходит.
- Сравнивайте подписи безопасно. Используйте функцию сравнения с постоянным временем выполнения, предусмотренную вашим языком или криптографической библиотекой. Обычное сравнение строк может завершиться при первом несовпавшем символе. Сначала убедитесь, что значения имеют ожидаемый формат и длину, затем сравните безопасным способом. Проверка: в обработчике нет сравнения подписи через обычный оператор равенства.
- Ограничьте срок годности запроса, если провайдер даёт временную метку. Проверьте, что метка входит в подписываемые данные, а допустимое окно задержки соответствует договорённостям о повторах и часам серверов. Слишком широкое окно увеличивает риск повторной отправки; слишком узкое — может отвергать легитимные доставки. Проверка: запрос за пределами настроенного окна отклоняется, а часы узлов синхронизированы.
- Защититесь от повторной бизнес-операции. Записывайте идентификатор доставки или события и обеспечьте идемпотентную обработку: повтор запроса не должен повторно списывать деньги, создавать заказ или отправлять письмо. Проверка: повторная доставка одного события не создаёт второго эффекта, в том числе при одновременной обработке двух копий.
- Разделите секреты. Используйте отдельный случайный секрет для каждого endpoint, проекта и среды. Не храните его в репозитории, URL или логах. При ротации заранее проверьте, поддерживает ли провайдер короткий период, когда принимаются старый и новый секреты. Проверка: компрометация одного ключа не открывает остальные интеграции, а старый ключ можно отключить без ручного изменения кода.
- Поставьте проверку до побочных действий. До успешной проверки подписи не запускайте обработчики, не отправляйте события в очередь и не меняйте состояние приложения. Ограничьте размер тела и время чтения запроса, чтобы некорректный или слишком большой запрос не занял ресурсы надолго. Проверка: запрос с плохой подписью не оставляет следов в бизнес-данных и не создаёт задачу в очереди.
- Не считайте IP-список заменой подписи. Фильтр по адресам может быть дополнительным барьером, если провайдер публикует актуальные диапазоны и ваша инфраструктура умеет их обновлять. Но адрес отправителя не подтверждает целостность тела и может измениться. Проверка: решение об аутентичности запроса принимается по подписи, а IP-фильтр лишь дополняет её.
- Проверьте ответ и наблюдаемость. Зафиксируйте, какие ответы запускают повторы у провайдера, и отвечайте только после безопасного принятия события. В логах оставляйте идентификатор доставки, результат проверки и причину отказа, но не секрет, подпись целиком и чувствительное тело. Проверка: по журналу можно найти сбой доставки, не раскрывая данные пользователя.
Подпись отвечает на вопрос «кто сформировал эти байты». Идемпотентность — на другой: «что произойдёт, если эти байты придут ещё раз».
Какой способ аутентификации выбрать
Для приёма событий обычно выбирают схему, которую поддерживает провайдер. Если вы сами отправляете вебхуки нескольким клиентам, выбор влияет на управление ключами и сложность интеграции.
| Подход | Что даёт | Цена и ограничения |
|---|---|---|
| HMAC с общим секретом | Подтверждает целостность тела и знание секрета. Хорошо подходит для схем, где провайдер заранее выдаёт ключ. | Обе стороны должны хранить секрет; его утечка позволяет формировать подписи. Ротацию и изоляцию ключей нужно организовать самостоятельно. |
| Асимметричная подпись | Отправитель подписывает закрытым ключом, получатель проверяет открытым. Получателям не нужно хранить общий секрет отправителя. | Подходит только если это поддерживают обе стороны. Нужно безопасно распространять и обновлять открытые ключи, а формат подписи всё равно задаёт протокол. |
| Фильтрация по IP | Отсекает часть запросов с адресов вне разрешённого списка. | Не подтверждает авторство и неизменность тела. Диапазоны могут меняться; как единственная защита недостаточна. |
Для проверки HMAC ориентируйтесь на RFC 2104; для HTTP-подписей с более общим форматом существует RFC 9421. Эти спецификации не заменяют контракт конкретного вебхука: наличие заголовка с подписью ещё не означает, что провайдер использует стандартный формат.
Когда что выбирать и что ломается
Если вы принимаете события от внешнего сервиса, реализуйте его документированный механизм подписи, а IP-фильтр добавляйте только как дополнительный контроль. Если вы проектируете собственную интеграцию с ограниченным числом доверенных систем, HMAC обычно проще внедрить, но заранее спроектируйте выдачу, изоляцию и смену секретов. Если получателям не следует доверять общий секрет, а обе стороны поддерживают асимметричную схему, рассмотрите подпись открытым ключом.
Частые сбои возникают не в криптографии, а на границах системы:
- Фреймворк разобрал JSON до проверки и потерял исходные байты. Решение — сохранить тело в исходном виде на входе и передать его проверяющему компоненту.
- Проверка проходит локально, но падает после прокси. Сравните, не изменяет ли промежуточный слой тело и не удаляет ли нужный заголовок.
- Событие принимается, но обработка выполняется дважды. Нужны устойчивое хранилище идентификаторов и защита от гонки, а не только проверка подписи.
- После ротации ключа легитимные доставки перестают проходить. Согласуйте момент смены с провайдером и предусмотрите ограниченное переключение ключей, если его схема это допускает.
- Логи помогают отладить подпись, но раскрывают содержимое заказа или персональные данные. Маскируйте тело и секреты; сохраняйте идентификатор события и техническую причину отказа.
Не принимайте запрос только потому, что он пришёл по HTTPS: TLS защищает канал передачи, но не заменяет проверку подписи на стороне приложения. И не отвечайте успешным статусом до того, как событие надёжно принято в обработку; иначе сбой между ответом и записью может потерять доставку.
Что делать дальше
Перед выкладкой соберите набор тестов: корректная подпись, изменённое тело, отсутствующий или неверный заголовок, просроченная временная метка, повтор события, слишком большое тело и одновременная доставка дублей. Отдельно проверьте ротацию секрета на тестовом endpoint. В продакшене следите за долей отказов проверки, числом повторных доставок и количеством дублей, которые остановила идемпотентность. Так вы заметите не только атаки, но и обычный рассинхрон конфигурации.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: GitHub Docs: Validating webhook deliveries, Stripe Docs: Verify webhook signatures
Частые вопросы
Можно ли проверить подпись после разбора JSON?
Если подпись верная, запрос точно безопасен?
Нужно ли проверять IP-адрес отправителя?
Что делать, если событие пришло второй раз?
Как безопасно сменить секрет вебхука?
Можно ли обойтись только HTTPS?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.