Если данные, которые я хочу аутентифицировать, состоят из нескольких значений, и я вычисляю MAC, просто объединяя значения, злоумышленник может «сдвинуть» символы в этих значениях, не аннулируя MAC. Как обычно и лучше всего решается эта проблема?
я нашел этот существующий вопрос о MAC-адресации нескольких сообщений, но я считаю, что предлагаемые решения не подходят для более чем двух сообщений.
Рассмотрим следующий надуманный пример:
Предположим, у меня есть сервер, на котором хранятся подлинные записи журнала для клиентов. Клиент записывает запись в журнал, аутентифицирует ее с помощью MAC и отправляет на сервер. Позже, когда клиент получит записи журнала с сервера, он сможет проверить их подлинность.
Допустим, записи журнала имеют следующую структуру:
{
createdAt: "1621012345",
сообщение: "первая запись"
}
Наивно я мог создать MAC для записи в журнале л
как
$$
mac = \text{HMAC}(K, l.createdAt \| l.message)
$$
куда $\|$ обозначает конкатенацию и $К$ является секретным ключом.
Если бы я сохранил эту запись журнала и MAC-адрес на сервере и получил их позже, сервер мог бы вернуть
{
создано по адресу: "1621012",
сообщение: "345первая запись",
mac: "<MAC, вычисленный выше>"
}
С 1621012 || 345первая запись
такой же как 1621012345 || первая запись
Я бы не заметил манипуляций при проверке MAC.
Обратите внимание, что в этом случае я должен фактически обнаружить манипуляцию, проверив затем длину создано в
. Но это работает, только если длина фиксирована, а не если бы я, скажем, имя автора
вместо отметки времени.
Я могу придумать следующие способы справиться с этим:
1. Вставьте разделитель
Если бы я рассчитал свой MAC как $mac = \text{HMAC}(K, l.createdAt \| \text{':'} \| l.message)$ Я считаю, что эта атака больше невозможна. На первый взгляд кажется проблематичным, что в сообщении может появиться символ-разделитель. Но это только делает невозможным однозначное восстановление значений из объединенной строки, что не имеет значения в этом сценарии. Я не могу придумать никакого способа сделать здесь расчет MAC неоднозначным. Безопасно ли это простое решение?
2. Хэш-значения перед конкатенацией
Я мог бы рассчитать MAC, например, как $mac = \text{HMAC}(K, \text{SHA256}(l.createdAt) \| \text{SHA256}(l.message))$ (или любую другую криптографическую хеш-функцию). Это гарантирует, что злоумышленник не сможет осмысленно манипулировать значениями, которые я объединяю. Это также гарантирует, что конкатенированные значения всегда имеют фиксированную длину. Добавляет ли хеширование какую-либо ценность по сравнению с первой идеей?
3. Аутентифицировать все структурированные данные
Я также мог бы рассчитать MAC для всего объекта JSON записи журнала. По сути, это означает, что у меня есть более сложные, осмысленные разделители (ключи и синтаксис). В общем, как JWT.
Обратите внимание, что этот подход также имеет некоторые недостатки, которые в основном сводятся к потере гибкости API и необходимости канонизировать JSON. Об этом есть отличная запись в блоге на https://latacora.micro.blog/2019/07/24/how-not-to.html.
Я пропускаю какие-либо хорошие решения для этой проблемы? Есть ли рекомендуемый способ справиться с этим?