<< Домой

Современная криптография и JWT

Исторически криптография может быть представлена в виде двух периодов, эпох. До и после появления ассиметричных алгоритмов. Первый насчитывает около 4к лет, второй около 50 лет. Разница м/у той и другой заключена в ключах, по-крайней мере внешне. Любая криптография содержит понятие ключа, в симметричных алгоритмах есть в общем случае один и только один ключ, в ассиметричных - два. Кроме того всякий алгоритм включает в себя операции шифрования и расшифрования (encryption & decryption). В симметричных алгоритмах оба действия производятся с помощью одного и того же ключа (говорят на одном ключе), в ассиметричных на разных. Более того в последних оба ключа равнозначны, нет понятия главный ключ или чего либо подобного. Их два и только два, что на одном зашифровано, может быть расшифровано только на втором и никак иначе, кроме перебора всех возможных значений конечно.

Но зачем всё это придумано?

Эти, так сказать, сложности возникли в ходе реализации одной практической задачи. Требовалось организовать защищенный обмен информацией, те обеспечить невмешательство в этот процесс третьих лиц. При этом нужна уверенность в аутентичности сообщения, те что на той стороне обмена именно тот субъект который нам нужен. При этом в наличии у нас открытый, незащищенный канал передачи сообщений. Других каналов нет, расстояние может быть любым, а времени на доставку даже курьером нет.

До 1976 года данная задача не имела решений. В этом году был найдено первое решение - алгоритм RSA[20] (аббревиатура от фамилий изобретателей, американцы, двое из которых программисты, третий математик). Необходимо сформулировать на прикладном уровне задачу, сразу станет яснее. Нужны две, по числу основных операций криптографии, односторонние функции. Аргументами первой является число для шифрования (исходный текст должен быть преобразован к числу) и первый ключ, аргументами второй функции должен быть результат расчета первой (шифротекст) и второй ключ. Результатом расчета второй является исходное число. В основании RSA лежит теория чисел[19], этот раздел математики относящийся к высшей арифметике вроде бы не представлен в школьной программе, не знаю как сейчас, раньше его не было. И может быть в силу этого как минимум непривычен. Изучает он св-ва натуральных чисел, это все целые, отрицательные и ноль. Для решения нашей задачи подошла другая задача - разложение (факторизация)[11] большого числа (несколько сотен шестнадцатиречных цифр) на простые множители. Даже для мощных ЭВМ это задача требует десятки лет. При этом, если число формируется определенным образом мы получаем доступ к некоторым известным его св-вам. А именно остаток от деления его на определённое число - модуль (первый ключ), а также без особого труда мы можем получить число обратное по модулю, это такое число которое будучи взято в степени -1 и умножено на исходное число при делении на тот же модуль даст в остатке единицу (второй ключ). Правда, порядок чисел огромен и поэтому исп-ся экспоненциальное представление и тут, поскольку нас интресуют остатки и только остатки от делений, на помощь приходит малая теорема Ферма. Дальнейшее погружение в высшую арифметику для целей заметки не имеет смысла, там еще много всякого любопытного,однако нужно быть профессиональным математиком чтобы пользоваться свободно такими знаниями.

Обобщим:
  1. у нас есть пара аргументов которые мы можем передавать в ф-ию шифрования вместе с текстом для шифрования и получать на выходе зашифрованное исходное сообщение (шифротекст).
  2. никто не может проделать обратное даже имея на руках те же аргументы и шифротекст.
  3. расшифровать исх. текст можно только с помощью других аргументов.

Прежде чем двинемся дальше, отметим некоторые особенности получившегося продукта.

Как видите, получился довольно спицифический продукт, применения которому, массово, нашлись в двух местах:
  1. Реализация некоторого криптографического слоя (TLS) поверх существующих прикладных протоколов: HTTPS, SSH, FTPS, POPS, IMAPS и тд.
  2. ЭЦП.
Действительно, именно в силу односторонности процедур шифрования/расшифрования можно сформировать общий секрет (сеансовый ключ) и организовать безопасную доставку его без необходимости встречаться отправителю и получателю. Как только сеансовый ключ доставлен, можно шифровать весь трафик, сравнительно легким, симметричным алгоритмом.

ЭЦП обеспечивает два требования:

В RSA ЭЦП реализована как проверка хеша (контрольной суммы) сообщения. Отправитель хеширует исходный документ, хеш криптуется на закрытом ключе, рез-т прикладывается к документу и отправляется. Получатель расшифрует ЭЦП на публичном ключе отправителя, произведет хеширование полученного документа тем же алгоритмом, затем сравнит рез-ты и, если те совпадают это значит, что документ не менялся по дороге. Факт расшифрования ЭЦП на открытом ключе отправителя удостоверит отправителя, подтвердит аутентичность документа. Нас, как web разработчиков, ЭЦП интересует гораздо больше, всё дело в JWT (Json web token). Это последний стандарт аутентификационных токенов, год выпуска 2015.

Наилучшим образом подходит для реализации RESTfull API и для использования в микросервисной архитектуре.[18]

JWT[19] по факту это небольшой массив из трех элементов соединенных через точку. Заголовок (header), нагрузка (payload) и подпись. Header и payload приводятся к JSON и кодируются в Base64. Полезные данные (payload) — это любые данные, которые вы хотите передать в токене, заметьте данные в токене открыты, стандарт не предусматривает никаких мер по защите токена от чтения, хотя ничто не мешает реализовать их самостоятельно. Из последнего следует, что токен не отменяет и не заменяет такие меры защиты как использование https. Стандарт[18] предусматривает несколько зарезервированных полей:

Все эти поля не являются обязательными, но их использование не по назначению может привести к коллизиям.[17]

Подпись может формироваться по разным алгоритмам, есть симметричные, но большинство ассиметричные. Наибольшую свободу проектируемая система аутентификации получит при использовании ассимметричных алгоритмов. В этом случае любые иные системы, участники инфообмена, например микросервисы, PWA, сайты или настольные приложения могут верифицировать токен не обращаясь к основному серверу аутентификации. Последнему достаточно предоставить им публичный ключ или сертификат проверки подписи JWT.

Поскольку нагрузка JWT произвольна, то "в руках предприимчивых людей это страшная штука" (с). Дело даже не в управлении мерами безопасности, хотя и это доступно, сколько в том, что имея такое средство можно проектировать значительно более гибкие сценарии обмена данными чем используя, например, старые добрые идентификаторы сессий. Например нам нужна ссылка, перейдя по которой пользователь получит доступ к определенной странице. При этом мы хотим остаться в RESTfull API, те не хотим хранить на сервере сведения о статусе аутентификации пользователя, нам нужно чтобы ссылка была ограничена по сроку годности, да и доступ к ней откроем только для определенной группы IP адресов и пусть она будет действительна только через 3 часа после формирования. Это возможно. Кроме этого можно её сделать одноразовой, правда для этого потребуется вести на сервере стоп лист использованных токенов и организовать его чистку по расписанию.

Должен предостеречь от использования самодельных криптографических средств, используйте только проверенные временем и сообществом библиотеки, слишком это специфичная тема.

Для повышения удобства и не в ущерб безопасности при использовании JWT рекомендовано использовать два токена: access и refresh. Первый прикладывается к "основным" запросам используется неограниченное кол-во раз, живет недолго, полчаса плюс/минус. Второй можно сделать одноразовым и по сроку годности год и более. Если время неактивности превысило срок жизни access токена, сервер не авторизует такой запрос, тогда, вместо отправки логина/пароля можно отправить refresh токен и получить обновленную пару access/refresh. Этот подход не является частью стандарта, однако является таковым de facto.

Литература
  1. https://habr.com/ru/post/443050/
  2. https://encyclopedia.kaspersky.ru/glossary/symmetric-encryption/
  3. https://ru.wikipedia.org/wiki/Симметричные_криптосистемы
  4. https://otus.ru/nest/post/726/
  5. https://3-info.ru/post/36614
  6. https://thecode.media/asymmetric/
  7. https://ru.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic
  8. https://ru.wikipedia.org/wiki/Сравнение_по_модулю
  9. https://habr.com/ru/post/144886/ (Введение в модулярную арифметику)
  10. https://ru.wikipedia.org/wiki/Китайская_теорема_об_остатках
  11. https://ru.wikipedia.org/wiki/Факторизация_целых_чисел
  12. https://planetcalc.ru/3754/
  13. https://ru.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/modular-inverses
  14. https://ilovecalc.com/calcs/maths/modular-inverse/1306/ (примеры вычисления обратного)
  15. http://crypt-online.ru/crypts/rsa/
  16. http://altaev-aa.narod.ru/security/Rsa.html
  17. https://codex.so/jwt
  18. https://datatracker.ietf.org/doc/html/rfc7519?roistat_visit=181883
  19. https://jwt.io/
  20. https://ru.wikipedia.org/wiki/RSA