Комментарии 60
вы не правильно пишите что application server должен знать секрет, какой же это секрет если о нем знает несколько сервисов
Смысл в том что application server может читать данные из payload без ключа, а когда надо их проверить (verify) то он может взять этот же токен и отправить его на сервер авторизации, а он уже зная секрет сообщит валидный это токен или нет.
Какой-то ключ application server должен знать, но это не обязательно должен быть тот же секрет, который использовался при создании токена. А может быть и тот-же, зависит от Signing Method — HMAC (shared key) или RSA/ECDSA (asymmetric).
давай те по порядку.
В статье говориться что секрет это то с помощью чего подписывается, далее в статье упоминается что секрет знают и сервер авторизации и сервер приложений, я лишь подчеркнул что это не правильно
Если подпись идет с помощью rsa то там ПУБЛИЧНЫЙ (не секретный) ключ и его может знать вообще кто угодно, а приватный ключ у сервера авторизации останется, как описали в коменте ниже.
При этом больше замечаний к статье не имею и в целом она очень адекватно написана, я лишь указал на то что неправильно трактовать можно прочитав статью
если несколько серверов или отдельных сервисов и использовать симметричное шифрование и раздавать этот ключ всем сервисам, то при компрометации одного из них, ключ станет известен злоумышленнику и он сможет выписать любые токены.
Для ситуации когда несколько сервисов, удобней использовать ассимитричное шифрование, когда есть одно место которое выдает токены и только оно знает приватный ключ, остальные сервисы используют публичный ключ для проверки подписи и не знаю приватный ключ, компрометация одного из сервисов не приводит к возможности генерировать произвольные токены злоумышленника, которые могут помочь скомпрометировать и другие сервисы.
в примере в статье речь о симметричном шифрование и секрет получается один и тот же что на auth сервисе, что на application.
да, именно об этом и идет речь в статье. И это, повторю в 3й раз, вполне правильная трактовка. С точки зрения JWT нет ничего неправильного в использовании симметричного ключа, это один из легальных способов.
Что касается «удобней» — это уже вопрос к вашей системе. Я могу придумать случаи когда использование HMAC будет удобней, но суть не в этом, а в том, что это один из нормальных методов подписи и верификации JWT.
я не говорю что HMAC или все симетричное шифрование это плохо и не правильно, я говорю что в приведенной в статье примере с сервисом авторизации и application, использовать один секрет не стоит, особенно если существуют и другие сервисы которые доверяют сервису авторизации, потому что это не безопасно не с точки зрения jwt, а скорее здравого смысла.
я не спорю, что для определенных случаев ассиметричный ключ будет безопасней, я всего лишь подчеркиваю, что категоричность приведенных выше цитат не соответствует действительности.
действительно категоричность моего комментария возможно и не правильна(с этой точки зрения я не подумал), но как мне кажется это очевидное замечание, что с точки зрения безопасности это(когда несколько сервисов и симетричное шифрование и все они знают один и тот же ключ) может быть не лучшим выбором, причем я ничего против безопасности jwt не имею и использую их уже несколько лет.
Зато симметричное шифрование гораздо быстрее асимметричного.
Вы пишете в первом сообщении, что сервер приложений сам проверить токен не может. Это полностью убивает сам смысл подписи токенов, так как сервер аутентификации может проверять валидность выданных им токенов и без криптографии, просто храня все выданные токены в БД.
Публичный ключ тоже требует защиты, правда не от узнавания, а от подделки. Поэтому и придумали PKI.
еще раз по порядку.
в случае если у вас несколько сервисов и один и тот же ключ используется во всех сервисах и доступен он между сервисами, если злоумышленник получит доступ к одному из сервисов, он сможет получить доступ к ключу, а с помощью ключа он сможет генерировать какие угодно токены, чем больше сервисов знает общий секрет, тем выше шансы на компрометацию.
В такой ситуации безопасней чтобы сервисы для валидации токена обращались к сервису авторизации и он уже проверял валидный он или нет, тем самым получив доступ к другим сервисам, они не смогут выпускать произвольные токены, а более правильно это ассимитричное шифрование, как человек тоже написал ниже, что есть приватный ключ и он известен в одном месте(в котором выдают токены), остальные сервисы знают только ПУБЛИЧНЫЙ ключ, с помощью которого могу проверять подписи, это публичный ключ можно хоть всему миру рассказать, главное что для генерация токена надо приватный ключ.
Хороший обзор, спасибо.
только сервер аутентификации и сервер приложения знают секретный ключ
Cекретный ключ они знают только если сервер аутентификации это и есть сервер приложения (т.е. это физически одно и то же приложение), если же они разные — то скорее будет использована пара private / public key. Вряд ли сервер аутентификации будет смело делиться со всеми серверами приложений своим приватным ключом.
Ответ: ресурсному серверу больше нет нужды стучаться в авторизационный сервер за проверкой валидности токена и его правами при каждом запросе от клиента. Он теперь в силах сам относительно дёшево проверить и валидность, и получить доп. информацию (например, права доступа) из самого токена. JWT гарантирует их аутентичность. Т.е. имеем упрощение серверной архитектуры и уменьшение нагрузки на авторизационный сервер.
UPD: ой, тред не читай @ сразу отвечай, ниже то же самое спросили
Или существуют случаи, когда «authorisation sever» и сервер, читающий и проверяющий JWT — не один и тот же сервер? Я с таким ещё ни разу не сталкивался. (Не считая кучки микросервисов, спрятанных за некой единой точкой входа — тогда можно применить схему от fuCtor ниже, и JWT для пользователя опять бесполезен)
К JWT это вообще отношения не имеет. Если безопасность не проблема — восстанавливайте сессии с authorisation server по куки (или еще как нибудь) невидимо для пользователя и открывайте ему сразу страницу его банковского счета, например.
От обычного сайта обычный пользователь будет требовать, чтобы его не разлогинивало. Из-за этого безопасность с короткоживущими токенами СНИЖАЕТСЯ: для постоянного автоматического релогина потребуется хранить пароль (или аналогичную инфу (refresh token?)) в открытом виде где-то рядом с токеном, и его с радостью уведёт злоумышленник вместе с токеном (mitm в эпоху повсеместного https почти нереален, скорее всего будет какой-нибудь RCE/XSS или тупо физический доступ к устройству). Придётся везде менять все пароли, похожие на утёкший. А вот если злоумышленнику попадёт классический долгоживущий токен, то достаточно будет просто удалить его из списка действительных.
Буду рад узнать, что я в чём-то не прав.
И как раз этот токен предназначен для того, чтобы пользователю не приходилось вводить пароль снова и снова.
Никто не мешает вам сделать JWT токен долгоживущим, если вы по какой-то странной причине считаете это нужным.
Никто не запрещает вам добавить проверку JWT токена в черном списке, как я сказал выше.
Разница и профит в том, что вам не надо напрягать сервер авторизации для такой проверки.
Но вообще говоря, короткоживущий токен рекомендуется в oAuth2 вообще и вне зависимости от механизма валидации.
Алсо, я вроде где-то читал, что refresh token отдавать юзеру вообще нельзя, что лишь добавляет путаницы в моём понимании
Вот это мне непонятно. Какой механизм может этому помешать? Передача рефреш токена, как бы она не просиходила, будет идти от клиента к серверу auth и в ответ на валидный refresh token auth server радостно создаст новый access token. Кроме условного «усиления refresh token» путем добавления туда чего-то типа source ip и/или агента или еще нечто в таком роде, я не вижу какой тут механизм помешает.
Насколько я себе представляю, этот рефреш токен должен быть у клиента и получит он его в момент login, вместе с access token, где его, теоретически можно украсть, например если есть физический доступ к компьютеру жертвы. Потом он (клиент) его будет время от времени посылать auth серверу для получения нового access token. Я не вижу как в этой схеме помешать злодею который завладел этим refresh token.
1.Если у вас конфиденциальный клиент, то можно требовать отправки client_id и client_secret вместе с refresh token для получения нового токена доступа. Т.о. если злоумышленник не знает вашего секрета, то получить новый токен доступа он не сможет.
2. На публичном клиенте, если злоумышленник знает client_id и refresh token — то это все что ему нужно :-).
Но, да, я согласен, это чисто теоретический и излишне параноидальный сценарий.
Я считаю, что делать токен короткоживущим достаточно. Т.к. за то время, пока вы узнаете, что токен скомпрометирован и добавите его в некий список, он уже скорее всего устареет в любом случае.
Хранилище чёрного списка может быть гораздо более быстрое, вплоть до нахождения в оперативной памяти адресного пространства сервера приложений.
Ещё два:
- блочить пользователя целиком до истечения токена
- вести чёрный список
Только если нужно сделать принудительный логаут, то нужно либо морочиться с рефреш-токенами (т.е., нельзя мгновенно с произвольного момента времени инвалидировать токен), либо вести базу инвалидных токенов (а это уже таблица в базе, сводящая на нет все преимущества токена с пейлоадом).
— есть два контура внешний и внутренний
— снаружи токен = oauth2 токен, со всеми плюшками, а внутри ходит JWT.
— при проверки oauth2 токена получаем короткоживущий JWT
— всё общение внутри уже идет используя именно JWT
Как результат на каждый запрос сервер авторизации запрашивается лишь раз, а остальные микросервисы довольствуются лишь данными из JWT, в принципе в подавляющем числе случаев достаточно UserID и набора прав.
либо вести базу инвалидных токенов (а это уже таблица в базе, сводящая на нет все преимущества токена с пейлоадом)
Т.к. размер этот базы на практике будет небольшим, а элементы в ней относительно короткоживущими (не сильно дольше времени жизни токена), то вполне можно сделать весьма быструю эффективную ее реализацию.
Если речь идёт именно о бане пользователя (а не отдельной его сессии), то просто отозвать права. Пользователь останется аутентифицированным, залогированным, но ничего защищенного проверкой прав в системе сделать не сможет.
К примеру, ip изменился, а сессия осталась та же. Почему изменился ip? Вариантов ответа несколько, часть из них совсем «неюзерфрендли», а даже скорее «хакераттакли». Поэтому привязка JWT к ip в несложных случаях повысит безопасность на достаточно много процентов.
TL;DR
Для понимания JWT раздел Структура JWT скорее вреден, чем полезен — он нужен только если кому-нибудь понадобится делать собственную реализацию, из-за слова payload и довольно большого объёма по сравнению с остальной частью статьи у меня сперва создалось впечатление, что подписываются все передаваемые данные, а не только лишь сам токен.
Статью можно сократить, раздел «Структура JWT» убрать под спойлер или заменить ссылкой на соответствующую статью в Википедии, и в самое начало жирным шрифтом вынести два комментария motomac:
Зачем это вообще нужно
По-моему, не сказано главного — чем оно лучше традиционных токенов.
Ответ: ресурсному серверу больше нет нужды стучаться в авторизационный сервер за проверкой валидности токена и его правами при каждом запросе от клиента. Он теперь в силах сам относительно дёшево проверить и валидность, и получить доп. информацию (например, права доступа) из самого токена. JWT гарантирует их аутентичность. Т.е. имеем упрощение серверной архитектуры и уменьшение нагрузки на авторизационный сервер.
И ответ на вопрос UncleAndyУ меня есть вопрос. Возможно глупый. Каким образом токен JWT защищен от перехвата третьей стороной?Так же как и обычный токен (никак).
Кто придумал в этом контексте перевести claim словом «заявка», когда тут однозначное, уже подтверждённое сервисом аутентификации, «утверждение»?..
Или это только для меня слово заявка ближе по смыслу к слову запрос, к чему-то недоказанному, что ещё требует подтверждения?..
Пять простых шагов для понимания JSON Web Tokens (JWT)