Конфигурация сессий и обработчики сохранений

Дата обновления перевода 2023-07-20

Конфигурация сессий и обработчики сохранений

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

Обработчики сохранений

Рабочий процесс PHP сессии имеет 6 возможных операций, которые могут произойти. Нормальная сессия следует open, read, write и close, с возможными destroy и gc (сбор мусора, который приведёт к истечению срока действия всех старых сессий: gc вызывается рандомно в соответствии с конфигурацией PHP, и в случае его вызова, он активизируется после операции open). Вы можете прочитать больше об этом здесь php.net/session.customhandler

Нативные PHP-обработчики сохранений

Так называемые нативные обработчики - это обработчики сохранений, которые либо компилируются в PHP, либо предоставляются PHP расширениями, вроде PHP-Sqlite, PHP-Memcached и т.д.

Все нативные обработчики сохранений внутренние в PHP и поэтому не имеют публичного API. Они должны быть сконфигурированы директивами php.ini, обычно session.save_path и потенциально другими директивами, связанными с драйверами. Конкретные детали можно найти в блоке документов метода setOptions() каждого класса. Например, предоставленный расширением Memcached может быть найден тут php.net.

В то время, как нативные обработчики могут быть активированы напрямую с использованием ini_set('session.save_handler', $name);, Symfony предоставляет удобный способ активировать их так же, как активируются пользовательские обработчики.

Symfony предоставляет драйверы для следующего обработчика сохранений в качестве примера:

Пример использования:

1
2
3
4
5
6
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;

$sessionStorage = new NativeSessionStorage([], new NativeFileSessionHandler());
$session = new Session($sessionStorage);

Note

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

Note

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

Пользовательские обработчики сохранений

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

Компонент Symfony HttpFoundation предоставляет несколько по умолчанию, и они могут служить примером в случае, если вы захотите написать собственные.

Пример использования:

1
2
3
4
5
6
7
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;

$pdo = new \PDO(...);
$sessionStorage = new NativeSessionStorage([], new PdoSessionHandler($pdo));
$session = new Session($sessionStorage);

Мигрирование между обработчиками сохранений

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

Вот рекомендуемый процесс работы миграции:

  1. Переключитесь на мигрирующий обработчик, в то время как ваш новый обработчик будет доступен только для записи. Старый обработчик ведёт себя как обычно, а сессии записываются в новый:

    1
    $sessionStorage = new MigratingSessionHandler($oldSessionStorage, $newSessionStorage);
  2. После этапа сбора мусора в вашей сессии, верифицируйте верность данных в новом обработчике.
  3. Обновите мигрирующий обработчик, чтобы он использовал старый только для записи, чтобы теперь сессии читались из нового обработчика. Этот шаг позволяет упрощённые откаты:

    1
    $sessionStorage = new MigratingSessionHandler($newSessionStorage, $oldSessionStorage);
  4. После верификации того, что сесси в вашем приложении работают, перейдите с мигрирующего обработчика на новый обработчик.

Конфигурация PHP-сессий

NativeSessionStorage может сконфигурировать бльшинство директив конфигурации php.ini, которые задокументированы в php.net/session.configuration.

Чтобы сконфигурировать эти настройки, передайте ключи (опустив начальную часть ключа session.) в качестве массива ключ-значение аргументу конструктора $options. Или установите их через метод setOptions().

Ради ясности, некоторые ключевые опции разъясняются в этой документации.

Время жизни куки сессии

По соображениям безопасности, токены сессии обычно рекомендуется отправлять в куки сессии. Вы можете сконфигурировать время жизни куки сессий, указав время жизни (в секундах), используя ключ cookie_lifetime в аргументе конструктора $options в NativeSessionStorage.

Установка cookie_lifetime, как 0 приведет к тому, что куки будет жить только пока браузер будет открыт. Обычно, cookie_lifetime устанавливается в достаточно большом количестве дней, недель или месяцев. Нередко также время жизни куки устанавливается в год или больше, в зависимости от приложения.

Так как куки сессии - это всего лишь токены клиентской стороны, они менее важны в контролировании мелких деталей ваших настроек безопасности, которые по умолчанию могут быть безопасно контролированы только с серверской стороны.

Note

Настройка cookie_lifetime - это количество секунд, которое должен жить куки, а не временная отметка Unix. Результирующий куки сесси будет иметь отметку истечения срока действия time() + cookie_lifetime, где кремя - токен от сервера.

Конфигурация сбора мусора

Когда сессия открывается, PHP рандомно вызывает обработчик gc в соответствии с вероятностью, установленной session.gc_probability / session.gc_divisor. Например, если они установлены, как 5/100 соответственно, это будет означать вероятность 5%. Таким же образом, 3/4 будет означать 3 из 4 шансов вызова, т.е. 75%.

Если активируется обработчик сбора мусора, PHP передаст значение, сохранённое в директиве php.ini session.gc_maxlifetime. Значение в этом контексте в том, что любая сохранённая сессия, которая была сохранена ране, чем gc_maxlifetime, должна быть удалена. Это позволяет утилизировать записи в зависимости от времени простоя.

Однако, некоторые ОС (например, Debian) проводят собственную обработку сессий, и устанавливают переменную session.gc_probability, как 0, чтобы остановить PHP от сбора мусора. Поэтому теперь Symfony перезаписывает это значение, как 1.

Если вы хотите использовать оргинальное значение, установленное в вашем php.ini, добавьте следующую конфигурацию:

1
2
3
4
# config/packages/framework.yaml
framework:
    session:
        gc_probability: null

Вы можете сконфигурировать эти настройки, передав gc_probability, gc_divisor и gc_maxlifetime в массиве конструктору NativeSessionStorage или методу setOptions().

Время жизни сессии

Когда создаётся новая сессия, что значит, что Symfony выпускает новый куки сессии клиенту, куки будет отмечен временем истечения действия. Оно рассчитывается путём сложения значения конфигурации прогона PHP в session.cookie_lifetime с текущим временем сервера.

Note

PHP будет выпускать куки только единожды. Ожидается, что клиент будет хранить этот куки всё время жизни. Новый куки будет выпущен только после разрушения сессии, удаления куки браузера или регенерации ID сесси, используя методы migrate() или invalidate() класса Session.

Изначальное время жизни куки может быть установлено путём конфигурации NativeSessionStorage, используя метод setOptions(['cookie_lifetime' => 1234]).

Note

Время жизни куки 0 означает, что срок действия куки истекает при закрытии бразура.

Время простоя сессии/Постоянное соединение

Часто возникают обстоятельства, в которым вы можете захотеть защитить или минимизировать неавторизованное использование сессии, когда пользователь отходит от терминала, оставаясь в системе, уничтожив сессию после определённого времени простоя. Например, для банковских приложений распространено выполнять выход пользователя через 5-10 минут бездействия. Установка времени жизни куки здесь неправильна, так как она может быть изменена клиентом, поэтому нам нужно установить срок истечения на серверской стороне. Самым простым способом реализации этого является сбор мусора, с достаточно высокой частотой. cookie_lifetime будет установлено в достаточно высоком хначении, а сбор мусора gc_maxlifetime будет установлен для уничтожения сессий после любого желаемого времени простоя.

Другой вариант - конкретно проверять, не истекла ли сессия после её начала. Сессия может быть разрушена по требованию. Этот метод обработки может позволить интеграцию истечения срока сессии в опыт пользователя, например, путём отображения сообщения.

Symfony записывает базовые метаданные о каждой сессии, чтобы предоставить вам полную свободу в этой сфере.

Ограничение кеша сессии

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

При построении, NativeSessionStorage устанавливает эту глобальную опцию, как "" (не отправлять заголовки) в случае, если разработчик хочет использовать объект Response для управления заголовками ответов.

Caution

Если вы полагаетесь на PHP сессии в обработке HTTP кеширования, вы должны вручную установить опцию cache_limiter в NativeSessionStorage, как непустое значение.

Например, вы можете установить её как значение PHP по умолчанию, во время построения:

Пример использования:

1
2
3
4
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;

$options['cache_limiter'] = session_cache_limiter();
$sessionStorage = new NativeSessionStorage($options);

Метаданные сессии

Сессии декорируются некоторыми базовыми метаданными для включения тщательного контроля настроек безопасноти. Объект сессии имеет геттер для метаданных, getMetadataBag(), который отображает экземпляр MetadataBag:

1
2
$session->getMetadataBag()->getCreated();
$session->getMetadataBag()->getLastUsed();

Оба метода возвращают временную отметку Unix (относящуюся к серверу).

Эти метаданные могут быть использованы для ясного истечения сессии при доступе, например:

1
2
3
4
5
$session->start();
if (time() - $session->getMetadataBag()->getLastUsed() > $maxIdleTime) {
    $session->invalidate();
    throw new SessionExpired(); // перенаправление на страницу истекшей сессии
}

Также возможно сказать, какое cookie_lifetime было установлено для конкретного куки, прочтя метод getLifetime():

1
$session->getMetadataBag()->getLifetime();

Время истечения куки может быть определено путём сложения созданной временной отметки и времени жизни.