Современная криптография и JWT
Исторически криптография может быть представлена в виде двух периодов, эпох. До и после появления
ассиметричных
алгоритмов.
Первый насчитывает около 4к лет, второй около 50 лет.
Разница м/у той и другой заключена в ключах, по-крайней мере внешне. Любая криптография содержит понятие
ключа,
в симметричных алгоритмах есть в общем случае один и только один ключ, в ассиметричных - два.
Кроме того всякий алгоритм включает в себя операции шифрования и расшифрования (encryption &
decryption). В
симметричных алгоритмах оба действия производятся с помощью одного и того же ключа (говорят на одном
ключе),
в
ассиметричных на разных. Более того в последних оба ключа равнозначны, нет понятия главный ключ или чего
либо
подобного. Их два и только два, что на одном зашифровано, может быть расшифровано только на втором и
никак
иначе, кроме перебора всех возможных значений конечно.
Но зачем всё это придумано?
Эти, так сказать, сложности возникли в ходе реализации одной практической задачи. Требовалось организовать защищенный обмен информацией, те обеспечить невмешательство в этот процесс третьих лиц. При этом нужна уверенность в аутентичности сообщения, те что на той стороне обмена именно тот субъект который нам нужен. При этом в наличии у нас открытый, незащищенный канал передачи сообщений. Других каналов нет, расстояние может быть любым, а времени на доставку даже курьером нет.
До 1976 года данная задача не имела решений. В этом году был найдено первое решение - алгоритм
RSA[20] (аббревиатура
от фамилий изобретателей, американцы, двое из которых программисты, третий математик). Необходимо
сформулировать
на прикладном
уровне задачу, сразу станет яснее.
Нужны две, по числу основных операций криптографии, односторонние функции. Аргументами первой является
число
для
шифрования (исходный текст должен быть преобразован к числу) и первый ключ, аргументами второй функции
должен
быть
результат расчета первой (шифротекст) и второй ключ. Результатом расчета второй является исходное число.
В основании RSA лежит теория чисел[19], этот раздел математики относящийся к
высшей
арифметике вроде бы не
представлен в
школьной программе, не знаю как сейчас, раньше его не было. И может быть в силу этого как минимум
непривычен.
Изучает он св-ва натуральных чисел, это все целые, отрицательные и ноль. Для решения нашей задачи
подошла
другая
задача - разложение (факторизация)[11] большого числа (несколько сотен
шестнадцатиречных цифр) на простые
множители.
Даже для мощных ЭВМ это задача требует десятки лет. При этом, если число формируется определенным
образом мы
получаем доступ к некоторым известным его св-вам. А именно остаток от деления его на определённое число
-
модуль
(первый ключ), а также без особого труда мы можем получить число обратное по модулю, это такое число
которое
будучи
взято в степени -1 и умножено на исходное число при делении на тот же модуль даст в остатке единицу
(второй
ключ).
Правда, порядок чисел огромен и поэтому исп-ся экспоненциальное представление и тут, поскольку нас
интресуют
остатки
и только остатки от делений, на помощь приходит малая теорема Ферма. Дальнейшее погружение в высшую
арифметику
для
целей заметки не имеет смысла, там еще много всякого любопытного,однако нужно быть профессиональным
математиком
чтобы
пользоваться свободно такими знаниями.
- у нас есть пара аргументов которые мы можем передавать в ф-ию шифрования вместе с текстом для шифрования и получать на выходе зашифрованное исходное сообщение (шифротекст).
- никто не может проделать обратное даже имея на руках те же аргументы и шифротекст.
- расшифровать исх. текст можно только с помощью других аргументов.
Прежде чем двинемся дальше, отметим некоторые особенности получившегося продукта.
- длина криптуемого (шифруемого) сообщения не может превышать длину наименьшего из ключей. На сей день
достаточно безопасной длиной ключа для
RSAсчитается 2048 bit и более. - криптование по асинхронному алгоритму требует примерно на два порядка больше процессорного времени чем симметричные алгоритмы, те примерно в 300-500 раз тяжелее.
- шифротекст (рез-т шифрования) не является семантически надежным, так получается потому что ключ не меняется внутри алгоритма и поэтому например повоторяющиеся слова в исходном тексте будут повоторятся и в шифротексте, только в шифрованном виде, конечно. Что делает возможным провести дешифрование, например с помощью частотного анализа.
- криптуемое сообщение должно быть преобразовано в числа посимвольно, криптуется каждое число в отдельности.
- Реализация некоторого криптографического слоя (TLS) поверх существующих прикладных протоколов: HTTPS, SSH, FTPS, POPS, IMAPS и тд.
- ЭЦП.
ЭЦП обеспечивает два требования:
- невмешательство третьей стороны в исходное сообщение.
- аутентичность сообщения, нам нужно убедиться в том, что отправитель именно тот кто указан в исходном сообщении.
В RSA ЭЦП реализована как проверка хеша (контрольной суммы) сообщения. Отправитель хеширует
исходный
документ,
хеш криптуется на закрытом ключе, рез-т прикладывается к документу и отправляется. Получатель расшифрует
ЭЦП
на
публичном ключе отправителя, произведет хеширование полученного документа тем же алгоритмом, затем
сравнит рез-ты и, если те совпадают это значит, что документ не менялся по дороге. Факт расшифрования
ЭЦП на
открытом
ключе отправителя удостоверит отправителя, подтвердит аутентичность документа.
Нас, как web разработчиков, ЭЦП интересует гораздо больше, всё дело в JWT (Json web token).
Это последний стандарт аутентификационных токенов, год выпуска 2015.
Наилучшим образом подходит для реализации RESTfull API и для использования в микросервисной
архитектуре.[18]
JWT[19] по факту это небольшой массив из трех элементов соединенных через
точку.
Заголовок
(header), нагрузка (payload)
и подпись. Header и payload приводятся к JSON и кодируются в Base64. Полезные
данные (payload) — это
любые
данные,
которые вы хотите передать в токене, заметьте данные в токене открыты, стандарт не предусматривает
никаких
мер
по
защите токена от чтения, хотя ничто не мешает реализовать их самостоятельно. Из последнего следует, что
токен не
отменяет и не заменяет такие меры защиты как использование https. Стандарт[18]
предусматривает несколько
зарезервированных полей:
- iss — (issuer) издатель токена
- sub — (subject) "тема", назначение токена
- aud — (audience) аудитория, получатели токена
- exp — (expire time) срок действия токена
- nbf — (not before) срок, до которого токен не действителен
- iat — (issued at) время создания токена
- jti — (JWT id) идентификатор токена
Все эти поля не являются обязательными, но их использование не по назначению может привести к коллизиям.[17]
Подпись может формироваться по разным алгоритмам, есть симметричные, но большинство ассиметричные.
Наибольшую свободу проектируемая система аутентификации получит при использовании ассимметричных
алгоритмов.
В этом случае любые иные системы, участники инфообмена, например микросервисы, PWA, сайты или настольные
приложения
могут верифицировать токен не обращаясь к основному серверу аутентификации. Последнему достаточно
предоставить
им
публичный ключ или сертификат проверки подписи JWT.
Поскольку нагрузка JWT произвольна, то "в руках предприимчивых людей это страшная штука" (с).
Дело даже не в управлении мерами безопасности, хотя и это доступно, сколько в том, что имея такое
средство
можно
проектировать значительно более гибкие сценарии обмена данными чем используя, например, старые добрые
идентификаторы
сессий. Например нам нужна ссылка, перейдя по которой пользователь получит доступ к определенной
странице.
При
этом
мы хотим остаться в RESTfull API, те не хотим хранить на сервере сведения о статусе
аутентификации
пользователя, нам нужно чтобы ссылка была ограничена по сроку годности, да и доступ к ней откроем только
для
определенной группы IP адресов и пусть она будет действительна только через 3 часа после формирования.
Это
возможно.
Кроме этого можно её сделать одноразовой, правда для этого потребуется вести на сервере стоп лист
использованных
токенов и организовать его чистку по расписанию.
Должен предостеречь от использования самодельных криптографических средств, используйте только проверенные временем и сообществом библиотеки, слишком это специфичная тема.
Для повышения удобства и не в ущерб безопасности при использовании JWT рекомендовано использовать два
токена:
access
и refresh.
Первый прикладывается к "основным" запросам используется неограниченное кол-во раз, живет недолго,
полчаса
плюс/минус. Второй можно сделать одноразовым и по сроку годности год и более. Если время неактивности
превысило
срок
жизни access токена, сервер не авторизует такой запрос, тогда, вместо отправки логина/пароля
можно
отправить
refresh
токен и получить обновленную пару access/refresh. Этот подход не является частью стандарта, однако
является
таковым
de facto.
Литература
- https://habr.com/ru/post/443050/
- https://encyclopedia.kaspersky.ru/glossary/symmetric-encryption/
- https://ru.wikipedia.org/wiki/Симметричные_криптосистемы
- https://otus.ru/nest/post/726/
- https://3-info.ru/post/36614
- https://thecode.media/asymmetric/
- https://ru.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic
- https://ru.wikipedia.org/wiki/Сравнение_по_модулю
- https://habr.com/ru/post/144886/ (Введение в модулярную арифметику)
- https://ru.wikipedia.org/wiki/Китайская_теорема_об_остатках
- https://ru.wikipedia.org/wiki/Факторизация_целых_чисел
- https://planetcalc.ru/3754/
- https://ru.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/modular-inverses
- https://ilovecalc.com/calcs/maths/modular-inverse/1306/ (примеры вычисления обратного)
- http://crypt-online.ru/crypts/rsa/
- http://altaev-aa.narod.ru/security/Rsa.html
- https://codex.so/jwt
- https://datatracker.ietf.org/doc/html/rfc7519?roistat_visit=181883
- https://jwt.io/
- https://ru.wikipedia.org/wiki/RSA