Поведение сессий, принятое по умолчанию, можно изменить, используя статические методы класса Zend_Session_Core. Все управление производится посредством Zend_Session_Core, включая конфигурирование через опции, предоставляемые расширением ext/session, с использованием метода Zend_Session::setOptions()
.
Когда запрошено первое пространство имен, Zend_Session_Core автоматически запустится, если не было уже запущено явно через метод Zend_Session_Core::start()
. Лежащие в основе PHP сессии будут использовать принятые по умолчанию настройки из Zend_Session_Core, пока они не будут изменены через метод Zend_Session::setOptions()
.
Для того, чтобы передать опции, просто передайте базовое имя (без приставки session.
) как часть массива методу setOptions()
. Если не были установлены опции, то Zend_Session будет сначала использовать рекомендуемые опции, затем установки по умолчанию из php.ini. Предложения по улучшению работы с опциями отправляйте в список рассылки fw-auth@lists.zend.com.
"Автоматическое" конфигурипрование этой компоненты с использованием Zend_Config_Ini:
Пример 21.11. Использование Zend_Config для конфирурирования Zend_Session
<?php $config = new Zend_Config_Ini('myapp.ini', 'sandbox'); require_once 'Zend/Session.php'; Zend_Session_Core::setOptions($config->asArray()); ?>
Используемый файл "myapp.ini":
Пример 21.12. myapp.ini
; Настройки по умолчанию для производственного сервера [live] ; bug_compat_42 ; bug_compat_warn ; cache_expire ; cache_limiter ; cookie_domain ; cookie_lifetime ; cookie_path ; cookie_secure ; entropy_file ; entropy_length ; gc_divisor ; gc_maxlifetime ; gc_probability ; hash_bits_per_character ; hash_function ; имя должно быть уникальным для всех приложений, использующих ; одно и то же доменное имя name = UNIQUE_NAME ; referer_check ; save_handler ; save_path ; serialize_handler ; use_cookies ; use_only_cookies ; use_trans_sid ; remember_me_seconds = <integer seconds> ; strict = on|off ; Наш тестовый сервер использует те же настройки, что и наш ; производственный сервер за исклочением тех, что переопределяются ниже: [sandbox : live] ; Не забудьте создать эту директорию и сделать ее доступной для чтения ; и записи через PHP save_path = /home/myaccount/zend_sessions/myapp use_only_cookies = on ; Когда индентификатор сессии сохраняется в куках, запрашивать TTL ; через 10 дней remember_me_seconds = 864000
Большинство опций, указанных ниже, не нуждается в дополнительных пояснениях сверх того, что написано в стандартной документации по PHP.
boolean strict
- отключает автоматический
запуск Zend_Session_Core
при использовании
new Zend_Session()
.
integer remember_me_seconds
- время
хранения идентификатора сессии в куках после того, как
агент пользователя завершит свою работу (т.е. когда окно
броузера будет закрыто).
string save_path
- Корректное значение
зависит от системы и должно указываться разработчиком с
использованием абсолютного
пути к директории, доступной для чтения и
записи процессом PHP.
![]() |
Угроза безопасности |
---|---|
Если путь доступен для чтения другими приложениями, то возможен угон сессий (session hijacking). Если путь доступен для записи другими приложениями, то возможно заражение сессий (session poisoning). Если этот путь используется совместно с другими пользователями или с другими PHP-приложениями, то это создает различные угрозы безопасности, включая кражу содержимого сессий, угон сессий и коллизии при "сборке мусора" (например, работа приложения другого пользователя может вызвать удаление файлов сессий вашего приложения).
Например, атакующий может зайти на сайт жертвы для
получения сессионных куков. Затем он изменяет путь
куков на собственный домен для того же сервера и
заходит на собственный сайт для выполнения
|
string name
- Корректное значение зависит
от системы и должно устанавливаться разработчиком, с
использованием короткого значения,
уникального для
приложения ZF.
![]() |
Угроза безопасности |
---|---|
Если настройки в |
boolean use_only_cookies
- Во избежание
появления дополнительных угроз безопасности не изменяйте
значение, принятое по умолчанию для этой опции, на
другое.
![]() |
Угроза безопасности |
---|---|
Если эта опция не включена, то аттакующий может
легко "фиксировать" идентификаторы сессии,
используя ссылки на атакуемый сайт вида
|
Введение: Наилучшей практикой в использовании сессий с ZF будет
использование куков вместо сохранения идентификатора сессии в
URL в качестве средства отслеживания отдельных пользователей. По
умолчанию эта компонента использует только куки для хранения
идентификатора сессии. Значением, сохраняемым в куках, является
уникальный идентификатор сессии. Расширение ext/session
использует этот идентификатор для поддержки однозначно
определяемой связи "один-к-одному" между посетителем сайта и
хранилищем постоянных данных сессии, уникальным для каждого
посетителя. Zend_Session* является оберткой к этому механизму
хранения ($_SESSION
) с объектно-ориентированным
интерфейсом. К сожалению, если атакующий получил доступ к
идентификатору сессии в куках, то он может угнать сессию
посетителя. Эта проблема не является присущей только PHP или
Zend Framework. Метод regenerateId()
позволяет
приложению изменять идентификатор сессии (сохраненный в куках
посетителя) на новое случайное значение. Замечание: Несморя на
то, что эти термины не равнозначны, для удобочитаемости мы будем
попеременно использовать "агент пользователя" и "веб-броузер".
Почему?: Если атакующий получил валидный идентификатор сессии, то он может имитировать реального пользователя (жертву) и затем получить доступ к конфиденциальной информации или манипулировать данными жертвы через ваше приложение. Изменение идентификатора сессии помогает защитить пользователя от угона сессии. Если идентификатор сессии был изменен и атакующий не знает его новое значение, то он не может использовать новый идентификатор сессии в своей попытке угона сессии посетителя. Даже если атакующий получил доступ к старому идентификатору сессии, то regenerateId()
перемещает данные сессии со старого идентификатора на новый, и поэтому данные этой сессии не будут доступны через старый идентификатор.
Когда использовать regenerateId(): Добавление
Zend_Session_Core::regenerateId()
в файл загрузки Zend Framework является одним из самых безопасных и надежных способов регенерации идентификаторов сессии в куках агента пользователя. Отсутствие условной логики, определяющей, когда регенерировать идентификатор сессии, не является изъяном в коде. Но несмотря на то, что регенерация при каждом запросе пересекает некоторые возможные пути атак, не все хотят мириться с небольшой потерей в производительности и пропускной способности, связанными с регенерацией. Поэтому приложения обычно пытаются определить ситуации, связанные с наибольшим риском, и только тогда регенерируют идентификаторы сессий. В случаях, когда привилегии сессии посетителя сайта "обостряются" (например, посетитель заново проходит аутентификацию до изменения его личного "профиля") или когда производятся "чувствительные" для безопасности изменения параметров сессии, используется regenerateId()
для регенерации идентификатора сессии. Если вы вызываете функцию rememberMe()
, то не используйте regenerateId()
, т.к. первая функция вызывает вторую. Если пользователь успешно залогинился на вашем сайте, используйте rememberMe()
вместо regenerateId()
.
XSS (межсайтовый скриптинг) - довольно распространенное явление. Лучше минимизировать возможный ущерб от них, следуя наилучшей практике программирования, чем думать, что этого никогда не случится с вами. Атакующему, использующему XSS, не нужно иметь прямой доступ к сетевому трафику жертвы. Если жертва уже имеет сессионные куки, то XSS с внедрением кода Javascript позволит атакующему прочитать куки и украть сессию. Если жертва не имеет сессионные куки, то, используя XSS с внедрением кода Javascript, атакующий может создать куку с заранее известным идентификатором сессии в броузере жертвы, затем установить идентичную куку в своей системе, чтобы угнать сессию жертвы. Если жертва посетила сайт атакующего, то атакующий может также сэмулировать и другие доступные для идентификации характеристики агента пользователя жертвы. Если ваш сайт имеет XSS-уязвимости, то атакующий может внедрить AJAX-код, который скрытно "заходит" на сайт атакующего, и атакующий может узнать характеристики броузера жертвы и о скомпрометированной сессии на сайте жертвы. Но несмотря на все это, атакующий не может изменить данные сессии на стороне сервера, при условии, что разработчик корректно установил значение опции save_path
.
Сам по себе вызов Zend_Session_Core::regenerateId()
в то время, когда сессия еще только начинает использоваться, не предотвращает атаку через фиксацию сессии, за исключением ситуации, когда вы можете отличить сессию, созданную атакующим, имитирующим личность жертвы. На первый взгляд это противоречит предыдущему утверждению, но до тех пор, пока мы не будем считать атакующим того, кто первый иницировал создание настоящей сессии на вашем сайте. Сессия сначала используется атакующим, который знает результат инициализации (regenerateId()
). Атакующий затем использует новый идентификатор сессии вместе с найденной XSS-уязвимостью или добавляет идентификатор сессии в ссылку на сайт атакующего (работает в том случае, если use_only_cookies = off
).
Если вы можете различать атакующего и жертву, использующих один и тот же идентификатор сессии, то это может решить проблему увода сессии. Тем не менее, такое распознавание обычно означает поиск компромисса с юзабилити, т.к. методы различения нередко являются неточными. Для примера, если запрос получен с IP в стране, отличающейся от IP запроса, при котором была создана сессия, то это может означать, что новый запрос производится уже атакующим. При выполнении следующих условий приложение сайта не сможет различить жертву и атакующего:
- атакующий первый иницировал сессию на вашем сайте для получения валидного идентификатора сессии
- атакующий использует XSS-уязвимость на вашем сайте для создания куки в броузере жертвы с валидным идентификатором сессии (т.е. фиксация сессии)
- атакующий и его жертва заходят через одну и ту же группу прокси-серверов (например, оба находятся за одним и тем же файрволом в большой компании - такой, как AOL)
Пример кода ниже намного затрудняет получение атакующим текущего идентификатора сессии жертвы, за исключением тех случаев, когда атакующий уже выполнил первые два шага из приведенных выше.
Обычно сессия заканчивается, когда агент пользователя завершает сеанс работы - например, пользователь закрыл окно броузера. Тем не менее, постле того как пользователь зашел в вашу систему, может быть желательным хранить его сессию 24 часа и даже больше. Программное обеспечение форумов обычно предоставляет пользователю возможность выбирать, сколько времени должна храниться сессиия. Используйте Zend_Session_Core::rememberMe()
для отправки обновленной сессионной куки агенту пользователя со временем жизни, по умолчанию равному remember_me_seconds
, который равен 2 неделям до тех пор, пока вы не измените это значение через метод setOptions()
. Для того, чтобы помешать угону или фиксации сессии, используйте эту функцию, когда пользователь успешно прошел аутентификацию и ваше приложение выполнило "регистрацию"
Эта функция дополняет rememberMe()
посредством возвращения сессионной куки к тому состоянию, при котором ее время жизни завершается, когда агент пользователя завершает сеанс работы (например, пользователь закрыл окно своего броузера).
Используйте этот метод для определения того, существует ли уже сессия для текущего агента пользователя/запроса. Он может использоваться до старта сессии и независимо от всех других методов Zend_Session и Zend_Session_Core.
Zend_Session_Core::destroy()
уничтожает все постоянные данные, связанные с текущей сессией. Это не влияет на переменные в PHP, поэтому ваши сессии с пространствами имен (экземпляры Zend_Session
) остаются доступными для чтения. Для выхода из системы установите необязательный параметр в true
(по умолчанию он равен true
), при этом будет удалена кука с идентификатором сессии в агенте пользователя. Установленный в true
необязательный параметр $readonly
блокирует возможность записи в данные сессии (т.е. в $_SESSION) для экземпляров Zend_Session и методов Zend_Session_Core.
![]() |
Исключения |
---|---|
По умолчанию |
Этот метод не делает ничего, кроме переключения флага в Zend_Session_Core для предотвращения дальнейшей записи в хранилище данных сессии (т.е.$_SESSION
). Одним из вариантов его использования является временное отключение возможности записи в хранилище данных сессии через экземпляры Zend_Session
или методы Zend_Session_Core
во время выполнения кода, связанного с отображением вида.
Попытка выполнить действия, подразумевающие запись через эти экземпляры или методы вызовет генерацию исключения.
Закрывает сессию, завершает запись и отделяет $_SESSION от средства хранения на сервере. Это завершит внутреннее преобразование данных для данного запроса. Необязательный параметр булевого типа $readonly позволяет отключить возможность записи (т.е. генерация исключения при попытке записи через любой метод Zend_Session или Zend_Session_Core).
![]() |
Исключения |
---|---|
По умолчанию |
Этот метод отправляет куку с уже истекшим временем действия, что вызывает удаление сессионной куки в агенте пользователя. Иногда этот метод используется для выхода из системы со стороны клиента.
Большинство разработчиков находят достаточной используемый по умолчанию механизм хранения сессионных данных.
Этот метод предоставляет объектно-ориентированную обертку для
session_set_save_handler()
.
Zend_Session использует этот метод для слабой связи экземпляров с сиглетоном Zend_Session_Core через нектоторую форму добавления зависимости.
Используйте этот метод для определения того, существует ли пространство имен с данным именем или определенный индекс в данном пространстве имен.
![]() |
Исключения |
---|---|
Если Zend_Session_Core не был помечен как доступный для чтения (например, до того, как Zend_Session_Core был запущен), то будет сгенерировано исключение. |
Вместо создания экземпляра Zend_Session для пространства имен и итерации по его содержимому для удаления каждой записи используйте метод namespaceUnset($namespace)
для быстрого удаления всего пространства имен и его содержимого. Как это справедливо для всех массивов в PHP, если переменная, содержащая массив, уничтожена, и этот массив содержал другие объекты, то эти объекты не уничтожаются, если они были сохранены в других массивах/объектах. Это означает, что они остаются доступными через другие переменные. Поэтому не следует рассчитывать, что namespaceUnset()
действительно сделает "реальное" удаление содержимого записей в пространстве имен. За более подробным объяснением обращайтесь к разделу References Explained в документации по PHP.
![]() |
Исключения |
---|---|
Если пространство имен недоступно для записи (например, после |
![]() |
Исключения |
---|---|
Если Zend_Session_Core не был помечен как доступный для чтения (например, до того, как Zend_Session_Core был запущен), то будет сгенерировано исключение. |
Zend_Session использует этот внутренний метод для получения значения $name
в пространстве имен $namespace
или массива содержимого пространства имен $namespace
. Этот метод не обязательно должен быть открытым. Если у вас есть разумные причины оставить этот метод открытым вместо использования Zend_Session, то, пожалуйста, пишите в список рассылки fw-auth@lists.zend.com. Участие в связанных с этим темах также приветствуется :)
![]() |
Исключения |
---|---|
Если Zend_Session_Core не был помечен как доступный для чтения (например, до того, как Zend_Session_Core был запущен), то будет сгенерировано исключение. |
Используйте метод getIterator()
для получения массива,
содержащего имена всех пространств имен, и с которым можно
производить итерации.
Пример 21.14. Уничтожение всех пространств имен
<?php $core = Zend_Session_Core::getInstance(); foreach(Zend_Session_Core::getIterator() as $space) { try { $core->namespaceUnset($space); } catch (Zend_Session_Exception $e) { return; // possible if Zend_Session_Core::stop() has been executed } } ?>
![]() |
Исключения |
---|---|
Если Zend_Session_Core не был помечен как доступный для чтения (например, до того, как Zend_Session_Core был запущен), то будет сгенерировано исключение. |