Всё, что стоит знать, и ничего лишнего.
Как формируется подпись
Распространенная схема формирует каноническую строку `${timestamp}.${requestBody}`, вычисляет `HMAC-SHA256(canonical, secret)`, кодирует результат в hex и передает дайджест и метку времени в заголовке подписи. Метка времени внутри подписанных данных защищает от атак повторного воспроизведения — ваша конечная точка должна отклонять веб-хуки старше 5 минут. Имена заголовков и точный канонический формат различаются между платформами, поэтому уточните их у своего поставщика, прежде чем писать код проверки.
Почему используются подписи HMAC, а не RSA?
HMAC симметричен — обе стороны разделяют секретный ключ, — что означает, что подписание и проверка примерно в 10 000 раз быстрее, чем RSA-2048. Для веб-хуков, где один SMSC может генерировать 50 000 DLR в секунду, подписание RSA занимает доминирующую долю ресурсов ЦП. HMAC-SHA256 на современном оборудовании выполняется за несколько микросекунд. Компромисс: подписать может любой, у кого есть секрет, поэтому секрет должен быть известен только платформе и вашей среде, храниться как любые другие учетные данные и ротироваться по запросу.
Подводные камни проверки
Три распространённые ошибки. Сравнение строк с помощью `==` вместо сравнения за постоянное время (атака по времени — используйте `crypto.timingSafeEqual`). Проверка подписи после разбора тела JSON (необходимо проверять исходные байты, а не пересериализованное представление — изменение порядка JSON нарушает хеширование). Забытое окно защиты от повторного воспроизведения для временной метки.
Помимо HMAC
Для регулируемых сред (банки, здравоохранение) некоторые платформы также поддерживают доставку веб-хуков по mTLS: отправитель предъявляет клиентский сертификат, который ваш балансировщик нагрузки проверяет до того, как запрос попадет в приложение. Это надежнее HMAC, поскольку доставка привязывается к аппаратному ключу, но оправдывает затраты только для действительно чувствительных нагрузок. Для большинства интеграций правильный ответ — HMAC-SHA256 поверх HTTPS.