Pull to refresh

Comments 19

Вот кажется, элементарная тема, но столько нюансов... И я более чем уверен что JWT использует не более 15% сервисов

От JWT нет пользы в большинстве проектов.

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

Если вы в JWT храните недостаточно данных (id пользователя и, допустим, роль) и затем запрашиваете все остальные данные в бд, то совокупного выигрыша нет.

Случайно "отклонил" комментарий к статье, извиняюсь. Мне бы хотелось все-таки на него ответить.

Комментарий был такой:

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

JWT токен не шифруется, а подписывается. Все что он содержит можно просто просмотреть декодировав текст из base64. Атака может быть, только на получение приватного ключа шифрования, если он слабый, для дальнейшей подмены токенов. —

Мой ответ:
Здесь сравнивалась пересылка данных в зашифрованном запросе (например, по протоколу tls). Обсуждаемая атака предполагалась на ключ шифрования запроса, а не на приватный ключ токена. Поскольку подбор ключей шифрования — трудоемкая операция, занимающая много времени, к моменту подбора ключа токен уже устареет и будет бесполезен, а вот пароль — нет. Отсюда я сделал вывод, что пересылка токенов безопаснее, чем пересылка паролей. Согласен, формулировка мутная, нужно перефразировать, спасибо.

Затронута интересная тема, спасибо! Но со своей стороны не могу не добавить:

  1. refresh token изначально выдается при авторизации пользователя вместе с access token

  2. Поле version инкрементируется при каждом изменении данных авторизации (пароля)

  3. Описываемая схема «Контроль версий» используется для того, чтобы заблеклистить refresh token (потому что система его не помнит и он не может быть просто добавлен в blacklist)

Еще бы услышать хотелось в чем смысл наличия id token и почему недостаточно иметь вместо него access token. А также про scope, implicit and explicit flow.

Если коротко - я не знаю. Насколько я понимаю, этот вид токенов используется в OpenId - протоколе, работающем поверх протокола OAuth2. Там архитектура значительно сложнее, чем описанная мной тут. Спасибо за вопрос, буду разбираться!

Ответ: конечно можно, но количество таких токенов будет существенно больше. Это увеличит объем потребляемой памяти, и замедлит запросы к БД. больше данных => медленнее поиск в БД.

В Redis поиск по ключу — это алгоритм сложности O(1). То есть не зависит от количества ключей и не замедлит запросы к БД.

Также Redis хранит данные довольно компактно и лимит по ключам на одном инстансе даже со скромным количеством памяти — десятки миллионов. Учитывая expiration, упереться в это вряд-ли получится для большинства сервисов.

Отсюда ещё раз вопрос: а так ли нужен JWT если инвалидировать токены нужно?

Про то, что алгоритм сложности редиса O(1) я не знал. Сейчас почитал, спасибо.
По вашему вопросу: уточните пожалуйста, а с чем мы сравниваем использование JWT?

Я вижу у JWT такие преимущества:
1. JWT универсальны. Вам будет легче проводить интеграцию со сторонними сервисами, если вы будете использовать универсальный формат ключей доступа.
2. У JWT есть payload. Мы можем добавить туда uuid пользователя, uuid клиента, и дополнительно все, что захотим. В любом стеке для них есть библиотеки, которые предлагают набор параметров для валидации и сами проводят ее. Если мы будем хранить ту же информацию, скажем, в редисе, нам придется самостоятельно писать код валидации.
3. Тому, кто придет работать с тем же кодом после нас, придется разбираться в логике валидации вмето того, чтобы использовать стандартные методы библиотек.
4. У библиотек, как правило, есть нормальная документация, где можно посмотреть зачем нужен каждый параметр.

Но, опять же, нужно понимать, с чем мы сравниваем JWT.

Мы его сравниваем с хранением payload в Redis и походом в него. То есть гоняем только ID-шник сессии, например, в httpOnly cookie и всё. Например, так умеют стандартные сессии в том же PHP.

Ок, понял. Ну, тогда в комбинации с редисом я разницы особой не вижу. Это просто альтернативная технология. Может кто-то подскажет?

Set-Cookie: refreshToken=<refresh-token>;

Насколько секьюрно хранить рефреш-токен в кукисах? Ведь в таком случае оба токена всегда передаются одновременно и полностью теряется весь смысл.

Они оба передаются не всегда, а лишь при запросе на обновление accessToken'а.

Вернее, правильнее делать так.

Так в том то и дело. Если используются куки, то как правило в качестве клиента подразумевается браузер. А браузер всегда отправляет вместе с запросом все куки, что у него есть. Соответственно, оба токена автоматически передаются всегда вместе. Поэтому я и спрашиваю.

С другой стороны, тут интересная ситуация, если клиент - это браузер. Допустим браузер был закрыт какое-то время, за которое access-токен просрочился. И вот я запускаю браузер, открываю сайт. Он идёт получать данные, а токен просрочился. И если в куках есть сразу два токена, то можно авторизовать юзера сразу. Если же refresh-токен хранится не в куках (что более правильно), то он будет доступен только после загрузки страницы, т.к. обратиться к нему можно будет только через javascript. То есть в случае decoupled-приложения, когда фронт и бэк по отдельности, и бэк выдаёт фронту токены для авторизации, то единственно правильным решением будет при первоначальной загрузке фронта грузить заглушку с лоадером, которая сначала проверит наличие токенов на клиенте, затем актуализирует их, и только потом будет грузить данные. Получается, что в вебе использование jwt удобно только в SPA, где нет SSR.

Про хранение rt НЕ в кукис, согласен.А так можно например использовать тот же axios. По дефолту запретить в запросах печеньки:

withCredentials: false

И юзать их лишь при ообновлении токена.

Тут скорее вопрос архитектуры.

Ну а accessToken всё же лучше хранить например в памяти приложения, тот же state в React.

Абсолютно не секьюрно, вы правы! я отредактирую это место. Сам я всегда передаю токены от сервера клинету в теле запроса, а от ключента к серверу через заглоовок Authorization. Пример с куками привел только для полноты картины, поэтому и пропустил это.

Про Bearer хочется подметить. Не обязательно писать именно Bearer. Там может быть абсолютно любое слово. Просто принятый стандарт.

Много проблем безопасности возникает напрямую если опираться на механизмы описанные в статье, и ещё больше есть подводных камней в статье не затронутых. Не стоит в таких вещах полагаться на ответы ChatGPT, он вам пишет то что вы просите. Разберитесь в общепринятых протоколах аутентификации и авторизации с использованием JWT, в OAuth2 с OIDC не зря столько сил вложено, не придумывайте своё.

А каким способом достигается "одноразовость" refresh token ? после использования вносим его в черный список?

хороший вопрос, я об этом не думал. Да, видимо нужно вносить его в black-list при выдаче новой пары

Sign up to leave a comment.

Articles