[jwtSession] Перенос сессии в куки браузера

Привет, друзья!

Вы задумывались, как работают сессии в MODX? Каждый раз, когда кто-то заходит на сайт, PHP генерирует ему уникальный id и сохраняет его в куку PHPSESSID. При этом в базе данных создаётся запись modSession с этим id и содержимым текущей сессии.

При каждом запросе на сайт передаётся кука с id, MODX делает запрос в БД, загружает сессию, а потом сохраняет в неё изменения. Минимум 2 запроса в БД каждый раз.

Что же нам предлагает JWT? Отказаться от всех этих действий на сервере, и выдавать всё нужное сразу в одном токене. Он может храниться в кукисах или в локальном хранилище браузера. Ну а дальше, при запросе, из него будет создана сессия пользователя. Соответственно, мы выкидываем работу с БД и не храним пользовательские сессии на сервере вовсе.

Конечно, сразу же встаёт вопрос — а что будет, если пользователь такую сессию подделает? Стандарт JWT ему этого не позволит. Токены можно прочитать, но не изменить, потому что они все подписаны надёжным алгоритмом с ключом на сервере, который пользователь не знает. Это теория, а теперь переходим к практике в MODX.

Наша любимая система позволяет заменить обработчик сессий через системную настройку session_handler_class, чем я и воспользовался, установив свой класс. После этого все скрипты сайта, которые работают с $_SESSION читают и пишут именно в JWT, а не в БД или файлы. MODX по привычке всё равно создаёт куку PHPSESSID, но в работе оно никак не используется.

К сожалению, быстро выяснилось, что хоть куки и не имеют ограничения по длине в RFC, браузеры ограничивают их 4096 байт. Это очень мало для рабочих сайтов, которые могут хранить массу данных. Поэтому jwtSession умеет разбирать один токен на несколько кук, а затем собирает их для чтения на сервере.


Так же мне показалось не очень клёвой идея чтения данных сессии. Мало ли что там сохранит программист? Поэтому, перед выдачей юзеру, её полезная нагрузка шифруется через openssl_encrypt тем же ключом, что используется для подписи JWT.
По умолчанию, кстати, это содержимое modX::site_id, но вы можете указать и системную настройку jwt_session_secret с произвольной фразой.

Вот так выглядит расшифрованный токен, как видите, содержимое сессии в data всё еще недоступно:

И распаковать его никак не получится, если вы не знаете секретный ключ.

Но, внимание, если у вас нет ничего особенного в сессии, то вы можете отключить шифрование настройкой jwt_session_encrypt, после чего можно будет свободно читать её содержимое на фронтенде, что пригодится для модерновых javascript сайтов, типа SPA на каком-нибудь VueJS.


Остальные настройки JWT куки регулируются стандартными настройками MODX: session_name, session_lifetime, session_domain и session_path.

В итоге мы получаем новое хранилище для сессий. Надёжное, быстрое, экономящее время, свободное место и запросы в БД. Ограничены такие сессии только настройками web-сервера, который может не пропускать большие заголовки.
Но тут уже помочь может только хостер, на modhost.pro, например, с этими настройками полный порядок.

Я не рекомендую устанавливать jwtSession на рабочие сайты прямо сейчас, лучше сначала погонять его на тестовых и понять, подходит ли он вам, или нет.

Прямо сейчас он уже работает на minishop2.com, можно посмотреть там в куки.

Обновлено 25.03.2019

Судя по всему, браузер Safari ломается, если сайт присылает кукисов суммарно на 4 килобайта. Так что, если вы хотите поддерживать этот браузер, то нужно чётко следить за тем, что пишется в сессию.
Василий Наумкин
24 марта 2019, 15:52
modx.pro
6
3 261
+11

Комментарии: 8

but1head
24 марта 2019, 16:08
0
JWT штука прекрасная, кроме того что токен не отозовать / не забанить пользователя. А если делать чекер на отозванные ключи — мы изобрели сессии.
    Василий Наумкин
    24 марта 2019, 16:25
    0
    У него же есть время выдачи. Просто считаешь невалидными все токены юзера, выданные до такой-то даты. Саму дату можно в профиль юзера прописать, который на сервере.

    Банится юзер так же на сервере. Office, например, автоматически проверяет, не заблокирован ли юзер, и если что выкидывает его через logout процессор.
      but1head
      24 марта 2019, 16:54
      0
      Проверка валидности (не заблочен ли юзер) тот же запрос в бд. Так же если юзер забанен а токен не истек — проблема. Ну это больше к самому jwt относится нежели modx.
        Василий Наумкин
        24 марта 2019, 17:01
        0
        Ну а MODX юзера всё равно будет из БД грузить, не важно, как сессии работают.

        Так что, тут можно не переживать.
    Павел Гвоздь
    24 марта 2019, 21:24
    0
    Как-то давно, когда я был программистом в одной забавной компании, сайт клиента просто перестал работать. Оказалось, что кол-во сессий в базе перевалило за несколько гигабайт данных, таблица с сессиями покрашилась и MODX не мог записать в неё ничего, из-за чего отказался так работать. Удалил таблицу с сессиями, создал заново, сайт заработал. Потом, конечно, настроили там что-то в базе (или на сервере), чтобы старые сессии почищались самостоятельно.

    Функция «Завершить все сеансы» из бек-энда поддерживается компонентом?
      Сергей Шлоков
      24 марта 2019, 22:12
      +1
      Функция «Завершить все сеансы» из бек-энда поддерживается компонентом?
      Ты сам-то как думаешь?

      Каждая технология предназначена для какой-то конкретной задачи. Лично я не вижу преимуществ JWT для обычных сайтов, которым не нужно масштабирование и репликация. Ещё для микросервисов сойдёт. Или если уж места на диске впритык. На MODX такие приложения не строят.
      В MODX сессия используются вовсю. Поэтому открытой её оставлять нельзя. И получается её нужно кодировать-раскодировать. И гонять туда-сюда. Не думаю, что это будет сильно быстрее. В общем везде есть свои плюсы и минусы. Всё нужно делать под конкретные задачи.
      Wassi Wassinen
      25 марта 2019, 02:06
      0
      После установки в Сафари такая история joxi.ru/DrlonoZFVn05BA
      Помогает «очистка истории».
        Василий Наумкин
        25 марта 2019, 06:31
        -1
        По всей видимости, элитный браузер Safari не может прожевать печенек суммой более 4 килобайт.


        Увы, это решение пользователям Safari подойдёт только при строжайшем контроле, сколько именно данных пишется в сессию.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        8