Что такое 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.