Глава 42. Защищенный режим

Содержание
Безопасность и защищенный режим
Ограниченные или недоступные в защищенном режиме функции

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

Безопасность и защищенный режим

Таблица 42-1. Конфигурационные опции, управляющие защищенным режимом и вопросами безопасности

ИмяЗначение по умолчаниюИзменяемость
safe_mode"0"PHP_INI_SYSTEM
safe_mode_gid"0"PHP_INI_SYSTEM
safe_mode_include_dirNULLPHP_INI_SYSTEM
safe_mode_exec_dir""PHP_INI_SYSTEM
safe_mode_allowed_env_varsPHP_PHP_INI_SYSTEM
safe_mode_protected_env_varsLD_LIBRARY_PATHPHP_INI_SYSTEM
open_basedirNULLPHP_INI_SYSTEM
disable_functions""PHP_INI_SYSTEM
disable_classes""PHP_INI_SYSTEM
Для получения более детальной информации о константах вида PHP_INI_* ознакомьтесь с функцией ini_set().

Краткое разъяснение конфигурационных директив.

safe_mode boolean

Включает/отключает защищенный режим в PHP. Для получения более детальной информации ознакомьтесь с разделом Безопасность.

safe_mode_gid boolean

По умолчанию в защищенном режиме при открытии файла выполняется проверка значения UID. Для того, чтобы немного смягчить это условие и выполнять проверку GID, необходимо установить значение on для флага safe_mode_gid. Определяет, использовать или нет проверку UID (FALSE) или GID (TRUE) проверку при обращении к файлу.

safe_mode_include_dir string

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

Начиная с PHP 4.2.0 значением этой директивы может быть список каталогов, разделенных двоеточием (точкой с запятой на windows-системах), что аналогично синтаксису include_path.

Указанное значение в действительности является префиксом, а не названием директории. Это означает, что запись "safe_mode_include_dir = /dir/incl" позволяет подключать файлы, находящиеся в директориях "/dir/include" и "/dir/incls", в случае, если они существуют. Если вы хотите указать доступ к конкретной директории, используйте завершающий слеш, например: "safe_mode_include_dir = /dir/incl/".

safe_mode_exec_dir string

В случае, когда PHP работает в защищенном режиме, system() и другие функции для выполнения системных команд и программ отклоняют выполнение программ, находящихся вне данной директории.

safe_mode_allowed_env_vars string

Возможность устанавливать переменные окружения - потенциальная брешь в безопасности. Значением этой директивы является список префиксов, разделенных двоеточиями. В защищенном режиме пользователь может модифицировать только те переменные окружения, имена которых начинаются с одного из указанных префиксов. По умолчанию, пользователю доступны переменные, которые начинаются с префикса PHP_ (например, PHP_FOO=BAR).

Замечание: В случае, если этой директиве указать пустое значение, пользователь получит возможность модифицировать любую переменную окружения!

safe_mode_protected_env_vars string

Эта директива содержит список переменных окружения, разделенных двоеточием, значение которых пользователь не сможет изменить, используя функцию putenv(). Значения этих переменных остаются защищенными, даже если их модификация разрешена директивой safe_mode_allowed_env_vars.

open_basedir string

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

Каждый раз, когда скрипт пытается открыть файл, например, при помощи функции fopen() или gzopen(), проверяется месторасположение файла. В случае, если он находится вне указанного дерева директорий, PHP отказывает в открытия файла. Все символические ссылки распознаются и преобразуются, поэтому обойти это ограничение при помощи символических ссылок невозможно.

Специальное значение . указывает, что базовой следует считать директорию, в которой расположен сам скрипт. В этом случае следует быть осторожным, так как рабочую директорию скрипта можно легко изменить при помощи функции chdir().

Опция open_basedir может быть отключена в конфигурационном файле httpd.conf (например, для некоторых виртуальных хостов) точно таким же образом как и любая другая директива: "php_admin_value open_basedir none".

Для Windows-систем разделителем списка директорий служит точка с запятой. Для всех других операционных систем в качестве разделителя используется двоеточие. В случае, если PHP работает как модуль веб-сервера Apache, все указания open_basedir для родительских директорий наследуются.

Указанное значение в действительности является префиксом, а не названием директории. Это означает, что запись "safe_mode_include_dir = /dir/incl" позволяет открывать файлы, находящиеся в директориях "/dir/include" и "/dir/incls", в случае, если они существуют. Если вы хотите указать доступ к конкретной директории, используйте завершающий слеш, например: "safe_mode_include_dir = /dir/incl/".

Замечание: Возможность работы с несколькими директориями добавлена в версии 3.0.7.

По умолчанию разрешен доступ ко всем файлам.

disable_functions string

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

Эта директива должна быть указана в php.ini. Вы не можете использовать ее, например, в httpd.conf.

disable_classes string

Эта директива позволяет вам запретить некоторые классы из соображений безопасности. В качестве значения она принимает список класов, разделенных двоеточием. disable_classes не зависит от того, используется Защищенный режим или нет.

Эта директива должна быть указана в php.ini. Вы не можете использовать ее, например, в httpd.conf.

Замечание: Эта директива доступна, начиная с PHP 4.3.2

Ознакомьтесь также со следующими конфигурационными директивами: register_globals, display_errors, и log_errors

В случае, если директива safe_mode установлена значением on, PHP проверит, совпадает ли владелец скрипта и владелец файла или директории, которыми оперирует скрипт. Например:
-rw-rw-r--    1 rasmus   rasmus       33 Jul  1 19:20 script.php 
-rw-r--r--    1 root     root       1116 May 26 18:01 /etc/passwd
выполние срипта script.php
<?php
readfile
('/etc/passwd');
?>
в случае использования защищенного режима приводит к следующей ошибке:
Warning: SAFE MODE Restriction in effect. The script whose uid is 500 is not 
allowed to access /etc/passwd owned by uid 0 in /docroot/script.php on line 2

Тем не менее, предусмотрена возможность вместо проверки на соответствие UID использовать более мягкую проверку на соответствие GID. Для этого необходимо использовать директиву safe_mode_gid. В случае, если она установлена значением On, используется более мягкая проверка GID. В противном случае, если установлено значение Off (значение по умолчанию), выполняется более строгая проверка на соответствие UID.

В качестве альтернативы директиве safe_mode вы можете ограничить все выполняемые скрипты жестко заданным деревом директорий при помощи опции open_basedir. Например (фрагмент конфигурационного файла httpd.conf):
<Directory /docroot>
  php_admin_value open_basedir /docroot 
</Directory>
При попытке выполнить тот же самый скрипт script.php с указанной опцией open_basedir вы получите следующий результат:
Warning: open_basedir restriction in effect. File is in wrong directory in 
/docroot/script.php on line 2

Вы также можете запретить отдельные функции. Следует заметить, что директива disable_functions может быть указана исключительно в конфигурационном файле php.ini, это означает, что вы не можете, отредактировав httpd.conf, установить индивидуальные значения для конкретного виртуального хоста или каталога. Если добавить в php.ini следующую строку:
disable_functions readfile,system
Результатом работы скрипта будет следующий вывод:
Warning: readfile() has been disabled for security reasons in 
/docroot/script.php on line 2