Почему механизм hmac безопаснее обычного хеширования
Отказ от ответственности: я не эксперт по безопасности. Для получения полной информации о HMAC ознакомьтесь с RFC 2104 .
При запуске код считывает файл данных и вычисляет для него подпись HMAC.
Альтернативные типы дайджеста
Двоичные дайджесты
Аутентификация HMAC должна использоваться для любой общедоступной сетевой службы и в любое время, когда данные хранятся там, где важна безопасность. Например, при отправке данных через конвейер или сокет эти данные должны быть подписаны, а затем подпись должна быть проверена перед использованием данных. Приведенный здесь расширенный пример доступен в файле hmac_pickle.py .
Первым шагом является создание функции для вычисления дайджеста для строки и простого класса, который будет создан и передан через канал связи.
Затем создайте буфер BytesIO для представления сокета или канала. В примере используется наивный, но простой для анализа формат потока данных. Записываются дайджест и длина данных с новой строкой. Далее следует сериализованное представление объекта, созданное pickle. Настоящая система не хотела бы зависеть от значения длины, поскольку, если дайджест неверен, вероятно, неверна и длина. Некоторая последовательность терминатора, которая вряд ли появится в реальных данных, была бы более подходящей.
Затем пример программы записывает в поток два объекта. первый записывается с использованием правильного значения дайджеста.
Второй объект записывается в поток с недопустимым дайджестом, полученным путем вычисления дайджеста для некоторых других данных вместо рассола.
Теперь, когда данные находятся в буфере BytesIO , их можно снова прочитать. Начните с чтения строки данных с дайджестом и длиной данных. Затем прочтите оставшиеся данные, используя значение длины. pickle.load () может читать непосредственно из потока, но это предполагает наличие надежного потока данных, а эти данные еще недостаточно доверены, чтобы их можно было извлечь. Считывать рассол в виде строки из потока, фактически не распаковывая объект, безопаснее.
После того, как обработанные данные находятся в памяти, значение дайджеста можно пересчитать и сравнить с данными, считанными с помощью compare_digest () . Если дайджесты совпадают, можно доверять данным и распаковывать их.
Выходные данные показывают, что первый объект проверен, а второй, как и ожидалось, считается «поврежденным».
Сравнение двух дайджестов с простой строкой или сравнение байтов может использоваться в атаке по времени, чтобы раскрыть часть или весь секретный ключ путем передачи дайджестов разной длины. compare_digest () реализует быструю, но постоянную функцию сравнения для защиты от временных атак.
К таким данным могут относиться например данные, передаваемые в запросах API, когда критически важна целостность передаваемой информации, или же при передаче данных из Web-форм.
Зачем это нужно?
Если отойти от научной формулировки, что же такое подпись данных и как это реализуется на практике?
Например, мы имеем исходный массив данных вида:
Самое простое, что мы можем сделать – это каким-то образом сериализовать массив (привести его в строковое представление), добавить в конец получившейся строки некий секретный ключ – набор символов известный только нам и получателю данных (пусть будет “mysecretkey”), после чего применить к этому какую-нибудь хеш-функцию, скажем, md5.
Какие можно встретить практические решения? В зависимости от того, важны ли значения массива или его ключи, можно встретить, например, такие реализации:
Какие есть плюсы и недостатки у данных реализаций?
Самый первый и очевидный плюс, но он же и единственный – это простота реализации. Минусы? Их масса, как минимум в качестве ключевых недостатков, можно привести:
- MD5 – уже старый алгоритм, который не считается стойким;
- Если нарушится последовательность параметров или значений – подпись не сойдется;
- Как быть с вложенными (многомерными) массивами?
- Либо ключи, либо значения.
В частности, таким образом, можно формировать более продвинутые CSRF-токены для форм, используя в качестве секретного ключа какой-нибудь внутренний идентификатор, привязанный к сессии пользователя. Тем самым мы решим сразу две задачи – и защиту от CSRF и контроль целостности набора передаваемых параметров – пользователь уже не сможет «поиграться» с полями формы и попробовать добавить или убрать что-нибудь из параметров.
Остальные три пункта требуют решения. С первым все достаточно просто – используем более современные и стойки хеш-аглоритмы с большей длиной шифрограммы, такие, как SHA256 или SHA512 и спим спокойно.
Второй пункт – тоже решается, если определиться, что элементы массива будут отсортированы по какому-то принципу, скажем, в алфавитном порядке.
Добавлеям перед сериализацией массива:
в результате чего, получаем массив, отсортированный по ключам в алфавитном порядке, и нам становится не важно, в какой последовательности были переданы переменные в массиве.
Следующая проблема решается уже не так просто. Пока мы работали с плоскими массивами все было достаточно просто – отсортировали, в строчку сложили с каким-нибудь разделителем типа ”;” – и готово. Но как же быть с вложенными (многомерными) массивами?
Во-первых функция ksort не рекурсивная, но это, конечно же не большая проблема и решение было найдено достаточно быстро:
Во-вторых, массив с вложенностями линейно в строчку уже не сложишь – нужно придумывать дополнительные правила (то есть, изобретать велосипед), или использовать уже «настоящую» сериализацию, такую как JSON, который учитывал бы все вложенные структуры. Использование JSON также решает и четвертую проблему, так как мы сериализуем сразу весь массив, не ограничиваясь отдельно его ключами или значениями.
Почему именно JSON а не простой serialize PHP? Выбор в пользу JSON упал не случайно, поскольку это очень популярный формат сериализации, с которым будет легко работать не только в PHP, но и в любых других популярных языках программирования, таких как Java. Наша реализация должна быть предельно легко переносима на другие платформы и с использованием JSON-сериализации это будет сделать проще всего.
В этом случае все перечисленные проблемы решаются, но встает вопрос с секретным ключом – делать простую конкатенацию ключа справа конечно можно, но это не очень эстетично, благо в PHP есть реализация HMAC с выбором произвольной хэш-фукции:
HMAC реализует дополнительное XOR данных с ключом и оборачивает сверху указанной хеш-функцией. Сам алгоритм внутри HMAC подробно описан в литературе по криптографии, или в википедии и описывать здесь, каким именно образом происходит шифрование данных на ключе мы не будем. Просто будем пользоваться этим стандартным аглоритмом.
Сводя все изложенное вместе, разработаем простой класс, который реализовывал бы все описанные действия для получения подписи с многомерного массива, вне зависимости от того, в какой последовательности находятся ключи внутри массива.
Итак, получился следующий незамысловатый код:
Вкратце разберем функциональность класса. В свойствах класса объявлены две приватные переменные для ключа и алгоритма, а также переменная $sign_param_name, в которой содержится имя параметра с подписью (по-умолчанию равно “hmac”), который будет использоваться при проверке данных методом check_data_hmac по-умолчанию.
В конструктор передается один обязательный параметр – это секретный ключ. По-умолчанию выбран алгоритм хеш-функции sha256. Можно переопределить алгоритм, передав его вторым параметром в конструктор. В случае, если переданный алгоритм не поддерживается системой, вернется значение константы E_UNSUPPORTED_HASH_ALGO (то есть -1).
Для создания подписи предусмотрен метод:
С ним все довольно просто – обязательный аргумент это данные, можно также использовать для формирования подписи другой секретный ключ, передав его вторым параметром.
Для проверки ранее созданной подписи мы реализовали метод
Метод принимает аргументы:
- $data – массив с данными;
- $key – необязательный аргумент, в котором можно передать секретный ключ. Иначе будет использован ключ из свойств объекта;
- $sign_param_name – имя элемента массива, содержащего контрольную подпись.
В остальном логика очень проста – собираем подпись, сравниваем регистронезависимо полученную подпись с подписью, переданной в данных.
Метод set_hash_algo, позволяет поменять алгоритм хеш-функции после создания экземпляра объекта. Функция рекурсивной сортировки массива реализована в качестве статического метода, чтобы ее можно было использовать вне экземпляра объекта где-то еще.
Примеры
Проиллюстрируем работу класса на простом примере:
На выходе получим:
Вместо заключения
Лёгкая статья про стандарты HMAC и JWT с небольшой теорией и исходным кодом.
Коллеги, позвольте вам рассказать о вещах, которые далеки от обычной разработки в 1С.
Вероятно, что сейчас у вас нет необходимости использовать HMAC и JWT, но время не стоит на месте, и, возможно, в очередном проекте интеграции вы задействуете описываемые ниже стандарты.
Часть первая, теоретическая.
Например, у нас есть три участника:
- 'Провайдер API' - сторонний сервис, который принимает запросы на отправку открыток и букетов
- 'Сервер' - серверная часть вашего приложения
- 'Клиент' - клиентская часть, с которой работают пользователи
'Провайдер API' предоставляет две вещи для выполнения запросов – это AccounID и SecretKey. 'Провайдер API' ни чего не знает про ваших пользователей, чтобы принять запрос на отправку открытки, ему нужно удостовериться, что просящий знает AccounID и SecretKey.
'Сервер' в свою очередь должен управлять тем, какие пользователи имеют право отправлять букеты, а каким разрешены только открытки.
- 'Клиент' - формирует запрос на отправку открытки для 'Сервера';
- 'Сервер' - проверяет права конкретного пользователя и если всё хорошо, то перенаправляет вызов на 'Провайдера API';
- 'Провайдер API' делает необходимые действия;
- Далее по цепочке обратно передается результат вызова.
Но что, если у нас клиенты генерируют десятки тысяч таких запросов, и не хотят долго ждать результат выполнения? Или наши запросы содержат потоковое аудио (для музыкальных открыток), которым не хотелось бы грузить 'Сервер'? Более того, а что, если 'Клиент' передает конфиденциальные сведения, которые и вовсе не должны попасть на 'Сервер' (букет с интимным посланием)?
Почему бы нам сразу не слать запросы с 'Клиента' на 'Провайдер API'?
Тогда нам придется 'Клиенту' сообщить AccounID и SecretKey, которые нужны 'Провайдеру API'. Но поскольку у нас разные клиенты имеют разные права (открытки, букеты) и в какой то момент у клиента права могут быть и вовсе отозваны, то мы не можем сообщать 'Клиенту' AccounID и SecretKey.
В этот момент нам и пригодится HMAC.
Благодаря HMAC мы можем построить работу следующим образом:
- 'Клиент' запрашивает у 'Сервера' специальный Token
- 'Сервер' делает Token с помощью HMAC, учитывая права пользователя и ограничивая действие токена по времени:
Теперь пользователь может обратиться напрямую к 'Провайдеру API' за конкретной услугой и предоставить Token, AccounID и ДатаВремяДоступа. 'Провайдер API' вычисляет Token и сверяет его с тем, что прислал 'Клиент' и той услугой которую 'Клиент' хочет получить.
В данной схеме 'Клиент' является той самой ненадежной средой. Фактически запрос должен делать 'Сервер', потому что 'Провайдер API' сказал свой SecretKey только 'Серверу'. Но наш 'Сервер' не хочет делать запросы и разрешает на время 'Клиенту' самостоятельно делать запросы. Наш 'Сервер' не доверяет 'Клиенту' и использует HMAC, чтобы обеспечить неизменность выданных разрешений на использование услуг 'Провайдера API'.
Часть вторая, считаем HMAC.
Давайте посмотрим под капот и узнаем, что же внутри функции HMAC.
Функция HMAC на вход принимает SecretKey и Message типа ДвоичныеДанные и вид хэш функции.
Функции BinLeft, BinRightPad, BinBitwiseXOR и BinConcat реализованы с использованием возможностей платформы, которые появились в версии 8.3.10.2168.
Теперь мы можем делать хэш и комбинировать данные для подписи любым способом.
Такой стандарт у нас есть, и называется он JWT.
Часть третья, пару слов про JWT
JWT (JSON Web Token) – это стандарт, по которому определено, в каком виде будет выглядеть токен для клиента. По сути JWT это строка, состоящая из трех частей соединенных точками: заголовок, данные и подпись.
Этот токен содержит:
и подпись (Signature):
Польза от JWT в том, что это стандарт и для этого стандарта уже готовы библиотеки на всевозможных платформах.
К этой статье приложена реализация JWT на чистом 1C:Enterprise 8.3.10.2168.
Например, вы делаете интеграцию со сторонним сервисом, и вам необходимо договорится об авторизации запросов от пользователей. С большой вероятностью сторонний сервис реализован на платформе, для которой есть готовая библиотека JWT. Вы как прогрессивный разработчик 1С теперь можете предложить использовать стандарт RFC 7519 – т.е. JWT. Каждый со своей стороны возьмет готовую библиотеку и вуаля – пользователи ходят напрямую в сторонний сервис.
Заключение
Благодарю, что прочитали эту статью. Надеюсь, вы нашли для себя полезное.
Пожалуйста, напишите в комментариях, как по вашему мнению можно было бы использовать JWT в мире 1С уже сейчас.
Основная цель:
- Для того чтобы можно было использовать имеющиеся хэш-функции без изменений, в частности, хэш-функций, которые уже есть в программном продукте, и их код уже доступен.
- Чтобы сохранить первоначальное исполнение хэш-функции без каких-нибудь значительных ухудшений.
- Использовать и обрабатывать ключи более простым способом.
- Для легкой заменяемости базовой хэш-функции в том случае, если более быстрая и более безопасная хэш-функция будет доступна позже.
Разработчики: Хьюго Кравчик, Михир Беллар и Ран Каннетти.
Содержание
Описание
В последние годы наблюдается повышенный интерес к разработке MAC на основе криптографических хэш-функций, например, MD5, SHA-1 или RIPEMD-160. А мотивы этого интереса просты:
- Криптографические хэш-функции обычно в программах работают быстрее, чем при использовании симметричных блочных шифров, такие как DES.
- Библиотечные коды для криптографической хэш-функции широко доступны.
- Хэш-функции, такие как MD5, не предназначены для использования в качестве MAC и не могут быть использованы непосредственно для этой цели, поскольку они не опираются на секретный ключ. Было сделано несколько предложений для включения секретного ключа в существующие хэш-алгоритмы. HMAC получил наибольшую поддержку.
Принцип работы
На рисунке 1 показан общий алгоритм HMAC:
HMAC параметры и обозначения
HMAC алгоритм использует следующие параметры:
Криптографический ключ
Размер ключа, К, должен быть больше или равен . Стоит обратить внимание, что ключи с размером больше чем L байт уже не существенно увеличивают криптографическую стойкость функции.
Псевдокод
Следующий псевдокод показывает как HMAC может быть реализован:
Возможные реализации
Представленные ниже языки программирования были выбраны из-за наличия стандартных библиотек, поддерживающих данный алгоритм. Пример использования реализации алгоритма на языке Python [1] :
Одна из возможных реализаций алгоритма на языке PHP [2] :
Примеры
Продемонстрируем пример работы алгоритма для различных входных данных.
и 20-байтовый ключ в шестнадцатеричном виде
Key:
0x707172737475767778797a7b7c7d7e7f80818283
1 шаг:
Дополняем Key нулевыми байтами до размера блока SHA-1(64 байта)
:
70717273 74757677 78797a7b 7c7d7e7f
80818283 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
2 шаг:
Побитовое исключающее ИЛИ
ipad:
46474445 42434041 4e4f4c4d 4a4b4849
b6b7b4b5 36363636 36363636 36363636
36363636 36363636 36363636 36363636
36363636 36363636 36363636 36363636
4 шаг:
Применим SHA-1 к результату, созданному на шаге 3
Hash((Key ipad)||text):
0d42b899 d804e19e bfd86fc4 4f414045 dfc9e39a
5 шаг:
Побитовое исключающее ИЛИ
opad:
2c2d2e2f 28292a2b 24252627 20212223
dcdddedf 5c5c5c5c 5c5c5c5c 5c5c5c5c
5c5c5c5c 5c5c5c5c 5c5c5c5c 5c5c5c5c
5c5c5c5c 5c5c5c5c 5c5c5c5c 5c5c5c5c
6 шаг:
Конкатенация результата хеширования на шаге 4 с результатом на шаге 5
( opad) || Hash((Key ipad)||text):
2c2d2e2f 28292a2b 24252627 20212223
dcdddedf 5c5c5c5c 5c5c5c5c 5c5c5c5c
5c5c5c5c 5c5c5c5c 5c5c5c5c 5c5c5c5c
5c5c5c5c 5c5c5c5c 5c5c5c5c 5c5c5c5c
0d42b899 d804e19e bfd86fc4 4f414045
dfc9e39a
7 шаг:
Применим SHA-1 к результату, созданному на шаге 6
HMAC(Key, Text) = Hash(( opad) || Hash((Key ipad)||text)):
2e492768 aa339e32 a9280569 c5d02626 2b912431
получили 20 байтовый HMAC(Key, Text)
Вопросы использования
Безопасность
Безопасность любой функции MAC на основе встроенных хэш-функции зависит от криптостойкости базовой хэш-функции. Привлекательность HMAC в том, что его создатели смогли доказать точное соотношение между стойкостью встроенных хэш-функции и стойкостью HMAC.
Читайте также: