Что такое HMAC-подпись и как проверить вебхук

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

HMAC (hash-based message authentication code) — стандартная конструкция, описанная в RFC 2104. Она берёт сообщение и секретный ключ и вычисляет с помощью хеш-функции, чаще всего SHA-256, короткую строку — подпись. Подделать её без знания секрета невозможно, а любое изменение сообщения, даже в один символ, даёт совершенно другую подпись.

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

Самая частая ошибка — считать подпись не от того, что пришло. Многие фреймворки сразу парсят JSON, и разработчик подписывает уже пересериализованный объект: порядок ключей, пробелы или экранирование отличаются, и подпись не совпадает. Подпись нужно проверять по сырому телу запроса, байт в байт. Вторая ошибка — сравнивать строки обычным оператором: для подписей используют сравнение за постоянное время, чтобы не дать атакующему подбирать подпись по времени ответа.

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

Moonvex подписывает вебхуки HMAC и передаёт подпись в заголовке Moonvex-Signature; точный формат подписи и пример проверки описаны в документации, а для Node.js есть SDK @moonvex/node.

Частые вопросы

Чем HMAC отличается от обычного хеша?

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

Почему подпись не совпадает, хотя секрет верный?

Чаще всего подпись считается не по сырому телу, а по пересериализованному JSON, или тело изменил прокси. Берите тело запроса до парсинга.

Можно ли передавать секрет вебхука в клиентский код?

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

Где это пригодится

Связанные термины

Начните принимать оплату сегодня

Аккаунт и первый проект за минуту, без абонентской платы.

Создать аккаунт