Вычислить метку — лёгкая часть
Корректно произвести хорошо изучено. Ошибки скапливаются на стороне проверки, где две проблемы ловят тех, кто верно сделал криптографию, но неверно — окружающую логику: как вы сравниваете метки и что на самом деле доказывает действительная метка.
Сравнивайте за постоянное время
Чтобы проверить, получатель заново вычисляет HMAC по сообщению и сравнивает его с меткой, предоставленной отправителем. Естественный способ сравнить две строки, обычное ==, возвращается, как только находит первый отличающийся байт. Этот ранний выход утекает время: метку, чей первый байт верен, отвергают чуть дольше, чем неверную сразу. Измеряя время ответа по множеству попыток, атакующий может восстановить верную метку байт за байтом — временная атака.
Защита — это сравнение за постоянное время, всегда проверяющее все байты, независимо от того, где лежит первое различие, так что затраченное время ничего не выдаёт о том, насколько близка была догадка. Большинство языков предоставляют такое:
- Node.js:
crypto.timingSafeEqual(a, b) - Python:
hmac.compare_digest(a, b) - Go:
hmac.Equal(a, b)
Никогда не проверяйте подпись обычным сравнением строк.
Действительная подпись — не свежий запрос
Даже идеально проверенный HMAC доказывает лишь, что сообщение произведено кем-то с ключом и не было изменено. Он ничего не говорит о том, когда. Атакующий, перехвативший легитимный подписанный запрос, может отправить ровно те же байты снова, и подпись по-прежнему пройдёт проверку. Это атака повтора, и она важна для всего, что вызывает эффект: платежа, изменения состояния, команды.
Чтобы остановить повтор, нужно нечто в подписанных данных, что делает каждый запрос уникальным и проверяемым:
- Метка времени в подписанной полезной нагрузке, причём сервер отвергает запросы вне короткого окна (учитывая дрейф часов).
- Nonce, уникальное для запроса значение, которое сервер регистрирует и отказывается принять дважды.
Оба должны находиться внутри подписанного содержимого, чтобы атакующий не мог их изменить, не сломав подпись.
Правило из двух частей
Запрос заслуживает доверия лишь тогда, когда его HMAC проверен за постоянное время и он свеж. Ошибитесь в любом — и подпись даёт ложное чувство безопасности. Это сторона проверки той же дисциплины, что и подписание запросов.
Инструмент HMAC позволяет вычислять и сравнивать метки для сообщения и ключа прямо в вашем браузере, без отправки чего-либо, чтобы вы могли проверить подпись вручную при разработке или отладке.