О хранении JWT токенов в браузерах


Открытый стандарт JWT официально появился в 2015 (rfc7519) обещая интересные особенности и широкие перспективы. Правильное хранение Access токена является жизненно важным вопросов при построении системы авторизации и аутентификации в современном Web, где становятся все популярнее сайты, построенные по технологии SPA.

Неправильное хранение токенов ведет к их краже и переиспользованию злоумышленниками.

Так и где хранить?


Рассмотрим основные варианты хранения JWT Access токена в браузере:

  1. Local Storage/Session Storage – метод не безопасный и подвержен атакам типа XSS, особенно если Вы подключаете скрипты из сторонних CDN (добавление integrity атрибута не может гарантировать 100% безопасность), либо не уверены что подключаемые Вами скрипты не имеют возможности «слить» данные из хранилищ на сторону. Более того если Local Storage доступен между табами то Session Storage доступен только в одной вкладке и открытие сайта в новой вкладке лишь вызовет новый раунд авторизации/рефреша Access токена.
  2. Хранение токена в локальной переменной внутри замыкания тоже не обеспечивает должной безопасности потому что атакующий может, например, проксировать функцию fetch и отправить токен на левый сайт. Так же это не решает проблему двух вкладок – нет безопасного способа передать токен из одной вкладки в другую.
  3. Cookies. Вот мы вернулись к старым «печенькам» которые использовались для хранения cookie sessions. Простое хранения Access токена в cookie чревато атакой CSRF. Более того оно не защищает от XSS атак. Для защиты от CSRF нужно ставить параметр Cookie SameSite в режим Strict– этим можно добиться того что все запросы, которые идут с других сайтов, не будут содержать Ваши credentials, что автоматически лишит атакующего возможности произвести CSRF атаку.
    В отличии от первых двух вариантов здесь есть и плюс – Access токен невозможно получить через JS если использовать флаг httpOnly, добавление Secure так же усилит защиту от сниффинга.

    Важным моментом является установка Cookie только для api домена/пути, чтобы запросы к публичной статике не содержали оверхед в header.

Что в итоге?


Cookies при правильном использовании являются адекватным и наиболее безопасным на данный момент решением для хранения JWT Access токена и должны следовать следующим правилам:

  1. Быть установленными для API домена/пути чтобы избежать оверхеда при запросах к статичным файлам (публичным картинкам/стилям/js файлам).
  2. Иметь флаг Secure (для передачи только по https).
  3. Иметь флаг httpOnly (для невозможности получения доступа из JavaScript).
  4. Атрибут SameSite должен быть Strict для защиты от CSRF аттак, запретит передачу Cookie файлов если переход к вашему API был не с установленого в Cookie домена.

На стороне сервера так же должно быть настроено:

  1. Content-Security-Policy – ограничение доверенных доменов для предотвращения возможных XSS атак
  2. Заголовок X-Frame-Options для защиты от атак типа clickjacking.
  3. X-XSS-Protection – принудительно включить встроенный механизм защиты браузера от XSS атак.
  4. X-Content-Type-Options – для защиты от подмены MIME типов.

Соблюдение этих мер вкупе с частой ротацией Access/Refresh токенов должно помочь обеспечить высокий уровень безопасности на сайте.

Ограничения


Не смотря на то что атрибут SameSite поддерживается во многих популярных браузерах , существуют так же браузеры которые не поддерживают его или поддерживают частично (привет IE и Safari для мака). Для этих случаев нужен fallback к CSRF токенам. В этом случае вместе с запросами к API надо передавать и CSRF токен. Правильный CSRF токен должен генерироваться сервером с учетом Fingerprint’a пользователя дабы минимизировать вероятность его подмены.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 102

    +7

    Неплохое начало, но статья как минимум мало имеет смысла без контекста.


    JWT вообще лучше не использовать без причины. Если у вас монолит приложение, вам JWT не нужно.


    Если у вас SPA и бекенд монолит, то куки лучше JWT.


    Если у вас бекенд на микросервисах, то JWT тут отлично пойдут, но должны храниться в кукисах. Так же нужно понять как отзывать, проверять. Понимать разницу и применение в шифрованных, подписанных. JWT с PKI или HMAC.


    Хранить в на стороне клиента JWT вообще бессмысленно, те же куки лучше делают это. Исключением есть OIDC implicit flow для мобильных устройств.


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

      0
        +1
        Статья не о том что JWT это хорошо или плохо, а о том где и как хранить токены.
        Конечно, микросервисы являються тем местом где лучше всего их применять, с другой стороны можно рассмотреть кейс, к примеру, сайта где API для SPA и для мобильного приложения общий.
          0

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

            0
            В чем смысл использовать JWT, если для валидации токена всё равно нужно обращаться в бд?

            Как раз смысл в том, чтобы по-максимуму не нужно было. Отсюда проблемы и проистекают. JWT валидируется без участия сервера его выдавшего и просто так отозвать его уже ставится невозможно.
              0

              Проблема именно в том, что токен может быть скомпрометирован. Как вариант — отзывать. Но как проверить отозван ли? Был ли использован refresh token? Или refresh токен можно использовать бесконечно, пока не истечёт?

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

                  Можете привести юзкейс, где jwt оправдан?
                  Все случаи, которые я могу представить, либо не требуют аутентификации, либо преимущество jwt нивелируется обращениями к бд.

                    0
                    Можете привести юзкейс, где jwt оправдан?


                    Обычно в JWT запихивают всякие credentionals. И сервис, получив запрос с токеном, формирует ответ без обращения к сервису авторизации за разрешениями. Потому что все разрешения уже в токене.
                      +2
                      В этом и смысл JWT, что там есть payload.
                      Но именно юзкейс, где JWT оправдан (не требует доп валидации токена, к примеру отзыв) я не могу ни найти ни придумать.
                      Можете привести такой пример, где JWT не требует доп валидации и общение сервисов не происходит внутри доверенной сети?
                        0
                        Где время жизни токена достаточно мало, чтобы не заморачиваться с отзывом. Скажем, я в своё время согласовал с СБ время жизни токена в 10 минут.

                        А однажды делал принудительный разлогин в SPA — при бане пользователя, браузер по вебсокету получал команду разлогиниться. Да, можно заблокировать разлогин, можно токен перехватить, но опять же ИБ устроило.
                      0
                      Могу попробовать вот такой пример. Если скажете как лучше буду благодарен.
                      image
                      Есть такой flow. Идея в том что account.company2 это некий внешний сервер который просто хранит логины пользователей как sso. account.company1 тут база с информацией о правах пользователя его группах которые могут использоваться some server, а также другими серверами. И без jwt account.company1 должен был бы делать дополнительный запрос к account.company2 для проверки пользователя.
                      Дабавить информацию о пользователе в account.company2 он нам не подконтролен.
                        0
                        Пользователь заходит на страницу авторизации
                        Пользователь авторизуется на сервере account.company2
                        После успешной авторизации происходит редирект на Some Server с пайлоадом в виде jwt
                        Правильно ли я понял?

                        Если да, то в случае, к примеру, если пользователь меняет пароль (либо происходит блок пользователя) на сервере account.company2, то доступ к account.company1 все равно сохраняется с предыдущим валидным jwt, так?

                        А если Some Server доверяет и account.company1 и account.company2, то какой смысл использовать аутентификацию между Some Server и account.company1?
                          0
                          пользователь меняет пароль (либо происходит блок пользователя) на сервере account.company2, то доступ к account.company1 все равно сохраняется с предыдущим валидным jwt, так?

                          Как правило именно так. Поэтому и совет, делать access токены с малым временем жизни, чтобы при запросе нового можно было проверить, что пользователь заблокирован или у него поменялся пароль, и потребовать заново ввести пароль.
                            +1
                            А насколько малое время жизни должно быть? =)
                            Из вашего же коммента refresh как правило хранят в бд. Тогда оверхед на использование refresh нивелирует преимущество access token.
                              0
                              Настолько, насколько считаете нужным. Минута, час, день, неделя.

                              refresh токен обычно нужен только для того, чтобы получить новый access токен. Если время жизни у последнего час, то раз в час примерно и будет обращение к БД. Access токена и его преимуществ это никак не касается.
                                +1
                                В данном случае преимущество = нет обращения к бд.
                                Но если делать access токен со слишком малым временем жизни, то нам необходимо чаще обращаться к бд для валидации refresh.

                                И все равно остается вопрос о консистентности данных.
                                  +1
                                  Эти обращения несоизмеримо реже происходят, поэтому выигрыш все равно существенный.
                                    +1

                                    Это выигрыш в производительности за счет безопасности. В любом случае даже короткий TTL — это "слепой период", на протяжении которого мы будем доверять любым устаревшим данным в JWT. В любом случае нам нужна stateful-инфраструктура для refresh-токенов, при этом мы по-прежнему не сможем отозвать JWT в любое время.

                                      +2
                                      А как еще получать выигрыш? Естественно надо чем-то жертвовать. Этот слепой период в подавляющем большинстве случаев несущественный. И есть простая методика, подходит вам JWT или нет. Если у вас жестокая секурность и надо запретить доступ кому-то вот прям сиюсекундно, то тут только классические сессии и валидация через бд при каждом вызове. Медленно, зато безопасно. Если не настолько жестокая, то дальше играться с периодом жизни access токена, насколько большой «слепой период» приемлем.

                                      Либо пробовать гибридные варианты. Ставить перед клиентом API gateway, который всегда валидирует токены через базу, а дальше передает их в сервисы, которые проверяют у них только подпись и доверяют содержимому. Все таки в современном интернете east-west трафика в разы больше, так что экономия все еще будет существенной.
                                        0

                                        JWT токены не стоит НИКОГДА отзывать. Они не задумывались для отзыва. Это антипатерн и проблемы с пониманием таких простых вещей как 10минутные jwt

                                          0
                                          JWT токены не стоит НИКОГДА отзывать. Они не задумывались для отзыва.

                                          Совершенно верно. Если чувствуется необходимость в отзыве, вам определенно не нужен JWT. Если вас не устраивает протухание данных в 10 минут — то же самое.


                                          JWT по определению предназначен для хранения кэшированных данных на стороне клиента, поэтому наследует все проблемы кеширования вроде инвалидации или несогласованности.

                                            0

                                            Ну так отзыв это и есть принудительная инвалидация кэша. Не сказать, что очень редкая вещь.

                                      0
                                      >нам необходимо чаще обращаться к бд для валидации refresh.

                                      Это может быть совсем другая БД на совсем другом сервисе. Основные операционные сервисы либо вообще в базу для валидации токена не ходят, либо ходят в быстрый KV только для проверки не отозван ли токен.
                                        0

                                        Так и сессии чаще всего хранят в кластере Redis.

                                          0

                                          На практике чаще всего в файлах, а если появляется несколько инстансов и балансер перед ними, то приклеивают. PHP :)

                                            0

                                            Интересно. В моей практике от файлов отходят при первом намёке на нагрузку даже на одном сервере.

                                              0

                                              В моей — это последнее что делают, когда стикки сессии проблем создают больше чем решают.

                                    0
                                    refresh как правило хранят в бд

                                    Как правило рефреш на клиенте в персистент хранилище, а токен доступа на клиенте в памяти приложения.
                                  0
                                  Правильно ли я понял?

                                  Почти. Я немного флоу упростил Some Server получает не напрямую jwt а code который обменивает на токен у account.company2. Но в общем виде да.
                                  Если да, то в случае, к примеру, если пользователь меняет пароль (либо происходит блок пользователя) на сервере account.company2, то доступ к account.company1 все равно сохраняется с предыдущим валидным jwt, так?

                                  Да и это более чем утсраивает так как вобще блокировка аккаунта на company2 нежелательна.
                                  А если Some Server доверяет и account.company1 и account.company2, то какой смысл использовать аутентификацию между Some Server и account.company1?

                                  В account.company1 хранятся реальные права пользователя для Some Server. Тоесть в account.company2 храниться просто ID пользователя(естественно что там хранится больше данных, но они нам не интересны и мы неможем там менять и добалять данные о пользователе). А вот в account.company1 и хранятся основные данные пользователя. Но там не хранится ни пароль ничего.
                                  company2 и company1 хотят иметь общую базу пользователей, но сервисы у компаний разные и чтобы каждая компания могла хранить разны права для своих сервисов нужны два разных account сервисы. Приэтом хочется иметь общую базу пользователей. Приэтом company2 уже имеет базу пользователей а company1 хотела бы эту базу пользователей использовать.
                                    0
                                    Я немного флоу упростил Some Server получает не напрямую jwt а code который обменивает на токен у account.company2

                                    Т.е. jwt хранится у Some Server и не передается пользователю?
                                    account.company1 не доверяет Some Server?

                                    Да и это более чем утсраивает так как вобще блокировка аккаунта на company2 нежелательна.

                                    А насчет смены пароля пользователя? Или при помощи чего происходит авторизация?
                                      0
                                      Т.е. jwt хранится у Some Server и не передается пользователю?
                                      account.company1 не доверяет Some Server?

                                      Да. Пользователю может не передаваться(смотря что мы под пользователем понимаем). Он ему впринципе не нужен(пользователю).
                                      Что под доверием подразумевается?
                                      А насчет смены пароля пользователя? или как происходит авторизация?

                                      Вся авторизация происходит только на стороне company2.
                                      Если нету куков у some server то идем авторизовываться если есть используем.
                                      Поидее some server использует jwt тольо для получение данных из account.company1. Посе этого оне ему ненужен. Также account.company1 может залезть в свою БД и проверить инфу о токене. Может проверить время выдачи токена и если ему подсовывают токен с более старой датой то отвергать его.

                                      EDIT:
                                      Также токен может быть просто с коротким временем например полчаса
                                        0
                                        Что под доверием подразумевается?

                                        То, что сервис может отправлять запросы без аутентификации. К примеру, может ли Some Server запросить данные о пользователе из account.company1 без аутентификации (отдать только id).

                                        Поидее some server использует jwt тольо для получение данных из account.company1.

                                        Может быть вы авторизовываете не то, что надо? Возможно вам нужно аутентифицировать Some Server на account.company1 (К примеру по ip)? Сделать так, чтобы Some Server мог получать инфу из account.company1 по любому пользователю?

                                        Или выдавая jwt вы тем самым выдаете Some Server разрешение на получение данных о пользователе, id которого заложено в jwt?
                                          0
                                          Нет так неполучится Some Server может быть клиентским приложением которое полностью крутится на устройстве пользователя.
                                            0
                                            Тогда в вашем flow Web Broser вообще не важен? =)

                                            Вы не отвечаете на мой вопрос про консистентность (про смену пароля) =)

                                            Вы при помощи jwt решаете проблему доступа к данным определенного пользователя?

                                            Т.е. если вы запрашиваете статичные данные с company2, то достаточно было бы любой электронной подписи.
                                            Вам jwt по сути нужен только для подписи статичных данных?
                                              0
                                              Тогда в вашем flow Web Broser вообще не важен? =)

                                              Важен приложение похоже по своей работе на pgadmin4.
                                              Вы не отвечаете на мой вопрос про консистентность (про смену пароля) =)
                                              Проблемма решается коротким сроком жизни токена.
                                              Т.е. если вы запрашиваете статичные данные с company2, то достаточно было бы любой электронной подписи.
                                              Вам jwt по сути нужен только для подписи статичных данных?
                                              Посути да. Но так-как company2 использует jwt и к нему куча готовых пиблиотек и он удобен, то почему бы и не jwt.
                                                0

                                                Вы предоставляете данные с сервера company1 только в том случае, если был авторизован в company2?
                                                Т.е. вы решаете проблему доступа к данным на сервере account1?


                                                Сколько у вас живёт токен?

                                                  0
                                                  Да на оба первых вопроса.
                                                  30 минут.
                                                    +1

                                                    В итоге у вас получается брешь?


                                                    Т.е. в течении 30мин злоумышленник может использовать невалидный токен?

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

                                                        Так я говорю про то, что Some Server может оказаться злоумышленником, иначе вы бы ему [Some Server] доверяли.
                                                        Т.к. some server имеет явный доступ к jwt

                                +1
                                Уже приводили — микросервисы. Если у вас SPA и куча API, к которым он обращается, а еще эти API внутри себя обращаются к другим API, то JWT может очень сильно сократить число прыжков до сервиса аутентификации. Большинство сервисов может полностью обойтись без них. Им достаточно проверить подпись, посмотреть payload, и готово. Если сервису нужно дернуть другой сервисы для выполнения запроса, то просто передается тот же самый токен. Цепочка сервисов может быть какой угодно длинной и за все время к БД за валидацией токена не надо обращаться ниразу. Это не только существенное ускорение системы в целом, но и повышение отказоустойчивости. Зависеть от БД с токенами такое себе решение.
                                А еще JWT полезно для межсервисной аутентификации, когда инициатором вызова является сам сервис, а не пользователь, где хочется закрыть доступ, но не хочется изобретать велосипед. Чтобы не держать специальный открытый endpoint для этого используются теже самые токены.
                                  +1
                                  Вы говорите про теорию Про теорию написано на той же вики)
                                  А вот юзкейс (именно практика), вот тут я не могу ни найти примера, ни придумать (всё упирается либо в доп валидацию либо в ненужность аутентификации).
                                  Можете привести именно пример использования?
                                    0
                                    Я говорю про то, как оно в моем проекте и работает. Я не знаю, что еще тут можно написать.
                                      0
                                      Напишите, пожалуйста, как происходит работа?
                                      К примеру:
                                      server1 хранит данные о пользователе и является sso
                                      server2 отвечает за статьи
                                      Пользователь авторизуется на server1 и получает jwt
                                      Пользователь отправляет запрос на server2 с ранее полученным jwt для создания новой статьи.
                                      0

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

                                        0

                                        Вы про jwt токен или впринципе про токен? =)
                                        Если про jwt, то я не вижу смысла в jwt. Он не жизнеспособен просто из-за того, что не гарантирует консистентность. А чтобы он это гарантированно его нужно валидировать на инвалидность (на то, что его не отозвали), но тогда легче использовать токен в виде рандомной строки, т.к. не будет оверхеда на подписи

                                          0

                                          Я про авторизацию на многих внутренних сервисах в общем.

                                0
                                Как минимум можно заменить тяжелый вызов к SQL базе, да ещё через ORM, has запросом к какому-нибудь шустрому KV типа редиса.
                                  0

                                  Тяжёлый запрос решается кешем.
                                  JWT же про авторизацию

                                    +1
                                    JWT не про авторизацию в целом. Просто в нём можно хранить и авторизационную информацию.

                                    А так, redis и выступает в роли кэша для одного типа запроса «есть ли такой-то токен в хранилище заблокированных/валидных».
                              +3
                              Для валидации самого токена обращаться к бд не нужно, достаточно проверить его подпись и экспирацию.
                              Дополнительное обращение к БД имеет место быть если нужно проверить что токен отозван, это не всегда нужно.
                              Самый простой пример: несколько сервисов, на страницах которых блок «профиль» в шапке сайта формируется без обращения к БД. Или пример микросервисов где каждый сервис будет знать ID, уровни доступа и т.п. данные пользователя без обращения к БД.

                                0

                                Можете описать подробнее пример с шапкой? Я не понимаю, что именно вы имеете ввиду. Откуда в данном случае был получен токен.
                                С микросервисами так же. Откуда они получают запросы? От доверенного источника? Внутри сети?

                                  +1
                                  Токен получается при аутентификации и вся информация, необходимая для шапки, уже в него зашита.

                                  С микросервисами: делаем api gateway, который выполняет ровно две функции: проверяет актуальность токена и маршрутизирует запрос дальше. А то и одну, на первом проверять и отправлять запрос на роутер. Остальным сервисам уже актуальность проверять не нужно, если запрос пришёл от доверенного api gateway (в простом случае из защищенного периметра по IP, а так можно по TLS c клиентским сертификатом заставить микросервисы общаться друг с другом)
                                0
                                Да, например SSO внутри корпоративной сети через OpenID Connect
                              +1
                              Соблюдение этих мер в купе с частой ротацией Access/Refresh токенов должно помочь обеспечить высокий уровень безопасности на сайте.

                              Наверное, никогда не смогу принять такие выражения в технических статьях:


                              • в купе с частой ротацией
                              • высокий уровень

                              Частый это сколько? 1, 2 или 10? В час, сутки или год?
                              Высокий это сколько?
                              Нельзя быть чуть-чуть беременной!

                                0
                                Согласен, Ваши замечания по поводу оценок обоснованы. Тут субъективная оценка с большим временем ротации. Чем меньше времени до рефреша токена тем меньше шансов его использовать повторно (навредить, исследовать систему и тд.), но больше нагрузки на бэк.
                                0

                                Уходили от кук и сессий и к ним же вернулись. Нормально так...

                                  +2
                                  В статье ничего про сессии не сказано, это Вы нафантазировали до кучи. А от кук особого вреда нет — тот же HTTP-заголовок
                                    0

                                    Ну по сути плюс-минус это сессии и есть, если в сессии хранить только ID юзера.

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

                                        В случае отсутствия необходимости экономить на SSO получается очень сходно.


                                        Кука + сессия: получаем ID сессии, вынимаем оттуда ID пользователя, вытаскиваем username и другие данные из базы для отображения профиля в UI.


                                        JWT: получаем ID пользователя, вытаскиваем username и другие данные из базы для отображения профиля в UI.


                                        Избежать можно если сунуть username и другие данные в JWT, но часть данных, как правило, не публична. Плюс добавляется проблема инвалидации токенов и вот это всё.

                                          –1
                                          Кука + сессия: получаем ID сессии, вытаскиваем сессию из базы, вынимаем оттуда ID пользователя, вытаскиваем username и другие данные из базы для отображения профиля в UI.

                                          fixed

                                            0
                                            вынимаем оттуда ID пользователя

                                            Нельзя ничего вынимать из айди сессии. Все, что с ней дозволено делать, это проверить ее наличие в базе и получить из базы же соответствие айди сессии пользователю (сессия это строка в базе, а не сам айдишник). Иначе можно передавать какие угодно ID в сессиях и представляться другим пользователем.
                                              0

                                              Из хранилища, соответствующего ID, конечно же.

                                          +1
                                          Классические сессии — хранение данных о сессии на сервере, в запросе только id сессии, сервер как-то сам их извлекает из хранилища. JWT — хранение данных сессии на клиенте, в запросе они все, хранилище сессий не нужно. Можно, конечно, скомбинировать, получив недостатки обоих способов.
                                            0

                                            Именно это хотел выразить. Очень часто начинают с JWT, вроде всё нормально, но после сталкиваются с проблемами:


                                            • А забаненного модератора как отлогинить?
                                            • Понадобилась ещё информация в токене. А что делать со старыми, где информации нет?
                                            • Надо сделать никнейм изменяемым. А он в токене...
                                            • Понадобились на UI данные, которые приватные (тут либо шифруют информацию в токене либо начинают комбинировать).
                                              0
                                              А что делать со старыми, где информации нет?

                                              Встречал подход с автоматическим детектированием в CD изменения модуля, отвечающего за токен, и если выявлено, то даунтайм вместо обачных нескольких секунд на прогон миграций — 16 минут (время жизни токена + 1 минута). :(

                                            0
                                            Отнюдь — сессия это целый механизм (обычно потребляющий ОП), который должен обеспечить сервер, и который очень неохотно масштабируется.
                                        0

                                        Я возможно чего-то не понимаю, но как при правильно настроенном CSP можно слить JWT из local storage на сторонний сервер?

                                          +1

                                          Reflected XSS Attacks / DOM XSS + Post

                                          +4

                                          А как быть, если токен выдаёт некий SSO-сервис и с ним клиенту нужно ходить на разные сервисы, расположенные на разных доменах? Например, те же микросервисы могут не иметь единой точки входа. Cookie с токеном на сторонние домены просто так отправить не получится.


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

                                            +1

                                            Api gateway сделать можно

                                            +1

                                            Объясните пожалуйста, я наверное что-то не понял, но если мы можем хранить в куки, то чем JWT будет отличаться от идентификатора сессии?


                                            Зачем он тогда нужен?


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


                                            Или я не правильно понимаю?

                                              0

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


                                              А в JWT можно прямо юзер айди записать. Или сразу список ролей/пермиссий, выданных этому юзеру (очень часто сервису неважно, что там за юзер — важно знать, есть ли у него доступ к той или иной операции)

                                                +2
                                                Данные сессии хранятся на сервере, на клиенте только их идентификатор. При использовании JWT данные в нём же и хранятся, на серверах обычно JWT не хранится. С одной стороны, это позволяет избегать лишних запросов от сервера к хранилищу сессий, избавиться от этого хранилища в принципе, сделать сервер более stateless. С другой, клиент эти данные может обрабатывать сам, без лишних запросов к серверу типа GET /session.

                                                Если не говорить о куче сервисов, к которым можно получить доступ с помощью одного токена, то JWT это просто аналог кук, в которые пишется всё, что сервер не хотел бы хранить на своей стороне между запросами клиента, а хотел бы видеть в них, запросах, без обращения к другим сервисам и хранилищам с гарантиями того, что эти данные он сам и отдал когда-то клиенту. Единственный плюс JWT по сравнению с обычными самоподписанными куками в таком сценарии: унифицированный формат и алгоритм формирования и проверки этих JWT кук. Готовые либы, много информации и т. п. Добротный такой готовый велосипед.
                                                0
                                                А как быть, если кроме браузера API юзают еще и мобилки?
                                                Для мобилок описанные проблемы безопасности не актуальны, а вот засунутый в куки токен выглядит не очень дружественно.
                                                  0
                                                  Если так сильно напряжно, то можно в токен записывать в теле или в куке он должен передаваться, с мобильных и других небраузерных клиентов слать в теле запроса, с браузера в куки, а на сервере разбираться соответствует ли фактический способ передачи заявленному в токене.
                                                    0

                                                    Нормально мобилки с куками работают. По крайней мере, под Android я работал. Вполне себе.

                                                      0
                                                      Ну понятно что можно, вопрос в другом
                                                      1) Это не особо дружественный к мобилкам интерфейс
                                                      2) Для клиентов, отличных от веб-браузера такое понятие, как «куки» вообще лишено смысла.
                                                      3) Средний «мидл» мобильный разработчик на аутсорсе при виде чего-то, минимально отличающегося от джейсона крякает и требует предоставить ему «нормальное API», а не «это говно». Понятно что они там джунов как мидлов продают, но суть дела не меняет.
                                                        +1
                                                        Для клиентов, отличных от веб-браузера такое понятие, как «куки» вообще лишено смысла.

                                                        Это часть спецификации HTTP, которую должны поддерживать все клиенты, а не только браузеры. Где-то в конце 90-х ещё можно было попасть на клиента, которые в куки не умел, приходилось самому парсить, хранить и формировать. Но это 20+ лет назад было.

                                                          0
                                                          Это часть спецификации HTTP, которую должны поддерживать все клиенты, а не только браузеры.

                                                          И под тот же Android java.net и обёртки нормально поддерживают.

                                                    +4

                                                    Есть мнение, что если совершена XSS атака, то утечка JWT — не самая большая ваша проблема.

                                                      +1

                                                      Но это не значит что от нее не надо защищаться

                                                      0
                                                      Можно в замыкании, но в service worker. Ни плагины, ни сторонний код со страницы не смогут его подделать
                                                        +1
                                                        Где Вы персистентно будете хранить токены в воркере?
                                                          0
                                                          в замыкании как переменную. Куки лучше, конечно, но у меня случай когда их нельзя использовать.
                                                            +1
                                                            Если хранить как переменную внутри замыкания то тогда юзер потеряет доступ когда воркер помрет. Подводные камни Service Workers
                                                              0
                                                              Это верно. У меня хранится в замыкании и там и там. Когда sw умирает, он переспрашивает у приложения. Подделать запрос от sw нельзя, подделать ответ можно, но в этом мало смысла.
                                                              Затем sw перехватывает запросы с api прикрепляет к ним accessToken и отправляет на api. Fetch на sw нельзя подделать.
                                                              + немного магии на проверки подлиности.
                                                        +2
                                                        Если нужно иметь доступ к токену из js и при этом не компрометировать безопасность, можно разделить токен и хранить в http-only cookie только подпись, а payload хранить в localStorage.
                                                          0

                                                          Нет никакой опасности, что localStorage может кто угодно прочитать. Если очень боитесь об этой ситуации, попробуйте использовать базу данных в браузере IndexDB. А обновления токена поместить в сервис воркер. Ах и да, используйте 5-10 минутные токены или посмотрите как эту проблему решил firebase в модуле auth. JWT создан так, чтоб хранитб в нем общедоступную информацию, которую может прочитать кто угодно. Если вы храните там закрытую информацию, то это проблема в использовании. Почитав комментарии понял, что есть много заблуждений и непониманий как использовать jwt правильно. Да и все, что вы передаете на frontend общедоступно, и подразумевает ваше согласие на то, что любой может прочитать и получить эту информацию

                                                            0
                                                            А чем использование IndexedDB отличается от localStorage?
                                                              0
                                                              Разницы нет. Так как браузерные расширения не имеют прямого доступа к IndexDB, (доступ и передачу через onMessage я не считаю за прямой ), я посчитал это как за преимущество
                                                                0
                                                                у браузерных расширений есть developer.chrome.com/extensions/content_scripts, не скажу за прям сейчас, но они могли до очень недавнего времени получить доступ к любым локальным хранилищам точно такой же как и у вашего приложения.
                                                                  0
                                                                  Я нашел только про chrome.store и про LocalStorage. Можете указать, где именно сказано про indexDB?
                                                                    0
                                                                    Content scripts работают в контексте страницы, они могут например, вставить script tag в DOM. Код в этом теге будет иметь доступ к window без ограничений
                                                                      0
                                                                      Но это не будет прямым доступом, о чем я написал выше
                                                                        0
                                                                        А какая разница, если плагин может прочитать данные из IndexedDB и отправить куда-то? Точно так же как и с localStorage. То есть чем IndexedDB безопаснее localStorage в плане безопасности?
                                                                          0
                                                                          Никак, все, что на frontend не безопасно. Не существует механизмов как-то безопасно хранить ключи и идентификацию пользователя. Тем более скрыть это. С localStorage так же как и с кошельком: оставите на видном месте — будет соблазн его спереть, а кто-то да и сопрет. Но это не защитит вас от грабителя, который целенаправленно идет вас грабить.
                                                                            +1
                                                                            Если очень боитесь об этой ситуации, попробуйте использовать базу данных в браузере IndexDB.

                                                                            А что вы имели ввиду в этом совете?
                                                                              0
                                                                              Я уже ответил
                                                            0
                                                            Честно говоря, никогда не видела, чтобы кто-то додумался хранить токены авторизации где-то, кроме Cookies.

                                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                            Самое читаемое