Запрет доступа PHP: настройки безопасности и права
Основное решение: комплексная блокировка PHP через конфигурацию веб-сервера и PHP
Как полностью запретить выполнение PHP-скриптов в определённых директориях?
Наиболее эффективный способ - отключить обработку PHP-файлов на уровне веб-сервера. Для Apache используется директива FilesMatch в .htaccess или в конфигурации виртуального хоста:
<FilesMatch \.php$>
Order Deny,Allow
Deny from all
</FilesMatch>
Php доступ запрещен (запрет доступа php)
Для Nginx аналогичный эффект достигается исключением PHP-файлов из обработки FastCGI:
location ~ \.php$ {
deny all;
}
Эти правила полностью блокируют доступ к любым PHP-скриптам в заданном каталоге. Сервер вернёт ошибку 403 Forbidden при попытке открыть *.php.
Проблема: если в каталоге лежат статические файлы (CSS, JS), то они не пострадают. Но если требуется разрешить доступ к некоторым PHP-скриптам (например, index.php), но запретить остальные, нужно использовать более тонкую настройку - например, разрешить только конкретные имена.
<FilesMatch "^(index|config)\.php$">
Order Allow,Deny
Allow from all
</FilesMatch>
<FilesMatch "\.php$">
Order Deny,Allow
Deny from all
</FilesMatch>
Ошибка: если не указать порядок обработки, правила могут конфликтовать. Рекомендуется проверять порядок FilesMatch - сначала разрешающие, потом запрещающие.
Варианты решений и их цели
Как ограничить доступ к PHP через директивы open_basedir?
Директива open_basedir ограничивает файловые операции PHP только указанными директориями. Это предотвращает чтение и запись за пределами разрешённой области.
; php.ini или .user.ini (для каталога)
open_basedir = "/var/www/site:/tmp"
Цель: если злоумышленник загрузит PHP-шелл, он не сможет получить доступ к системным файлам (например, /etc/passwd).
Типичная ошибка: указание путей с завершающим слешом и без - для open_basedir слеш не требуется. Нельзя использовать символы подстановки, только точные пути. При указании нескольких путей в Windows разделитель ;, в Unix - :.
Как отключить опасные функции через disable_functions?
В php.ini можно задать список функций, которые не должны выполняться ни в одном скрипте.
disable_functions = exec, system, shell_exec, passthru, popen, proc_open, curl_exec, curl_multi_exec, parse_ini_file, show_source, highlight_file
Цель: предотвратить выполнение команд ОС, сокетов и других потенциально опасных операций.
Ошибка: отключение слишком большого числа функций может сломать легитимный код. Перед включением нужно проверить, какие функции используются в приложении.
Дополнительный нюанс: некоторые функции (например, exec) могут быть переопределены через расширения. disable_functions не блокирует функции, вызванные через отражение (ReflectionFunction).
Как запретить выполнение PHP в определённых директориях через .htaccess с AddHandler?
Один из популярных методов - удалить ассоциацию расширения .php с обработчиком PHP для конкретной папки:
RemoveHandler .php
RemoveType .php
После этого Apache перестанет передавать PHP-файлы интерпретатору, и они будут отдаваться как обычный текст (или скачиваться).
Важно: если используется FastCGI или php-fpm, директивы RemoveHandler могут не сработать. В таких случаях применяют блокировку через FilesMatch.
Как изолировать выполнение PHP через chroot или контейнеры?
Для глубокой изоляции можно настроить PHP-FPM с опцией chroot. Скрипт будет видеть только корневую файловую систему, заданную в конфигурации пула.
; pool.d/example.conf
[example]
chroot = /var/www/chroot
Цель: полная изоляция - даже если злоумышленник выполнит код, он не выйдет за пределы chroot-окружения.
Сложность: нужно скопировать все необходимые системные файлы (библиотеки, устройства) в chroot-каталог. Малейшая ошибка приведёт к неработоспособности приложения. В современных сценариях чаще используют Docker.
Как ограничить доступ PHP к файловой системе через PHP_INI_SYSTEM директивы?
Некоторые параметры, такие как allow_url_fopen и allow_url_include, могут быть отключены, чтобы предотвратить удалённые включения файлов.
allow_url_fopen = Off
allow_url_include = Off
Цель: предотвратить RFI- и LFI-атаки.
Проблема: отключение allow_url_fopen может нарушить работу легитимных функций, таких как file_get_contents('https://...'). Нужно оценить необходимость.
Как запретить загрузку PHP-файлов через веб-интерфейс?
В конфигурации сервера можно установить размер загружаемых файлов и типы. Для Apache в .htaccess:
php_value upload_max_filesize 2M
php_value post_max_size 3M
php_value max_execution_time 30
Но это не блокирует загрузку PHP-сценариев. Лучше комбинировать с проверкой MIME-типа в приложении.
Расширенные примеры и результаты
Пример 1: Блокировка PHP только для определённых расширений (кроме .php7, .phtml)
# .htaccess
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|phps)$">
Order Deny,Allow
Deny from all
</FilesMatch>
Результат: любой запрос к файлам с указанными расширениями вернёт 403. Если нужно разрешить, например, .php7, его нужно исключить из шаблона.
Пример 2: Использование PHP-опции auto_prepend_file для блокировки
Можно определить скрипт, который будет выполняться перед каждым PHP-запросом и проверять, разрешена ли директория:
; php.ini или .user.ini
auto_prepend_file = /var/www/block.php
Содержимое block.php:
<?php
$restricted_dirs = ['/var/www/uploads', '/var/www/cache'];
$script_dir = dirname($_SERVER['SCRIPT_FILENAME']);
foreach ($restricted_dirs as $dir) {
if (strpos($script_dir, $dir) === 0) {
http_response_code(403);
die('Access denied');
}
}
Результат: при попытке выполнить скрипт из /var/www/uploads/test.php браузер получит 403 Forbidden.
Пример 3: Блокировка PHP через расширение Suhosin
Suhosin - патч для PHP с дополнительными возможностями блокировки. Пример конфигурации:
; php.ini
extension=suhosin.so
suhosin.executor.func.blacklist = "exec,system,passthru"
suhosin.executor.eval.blacklist = "include,require"
suhosin.mail.protect = 2
Результат: вызов указанных функций завершится ошибкой, даже если они не указаны в disable_functions. Также Suhosin добавляет защиту от атак типа null byte.
Пример 4: Запрет доступа к PHP через Nginx с проверкой IP
Разрешить выполнение PHP только для определённых IP-адресов администраторов:
location ~ \.php$ {
allow 192.168.1.0/24;
allow 10.0.0.1;
deny all;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
Результат: PHP-скрипты выполняются только для пользователей из указанных подсетей. Остальные получают 403.
Пример 5: Блокировка PHP с помощью PHP-расширения disable_classes
Можно полностью запретить использование определённых классов (например, для отключения доступа к PDO):
; php.ini
disable_classes = "PDO,PDOStatement,ReflectionClass"
Результат: любой код, пытающийся создать экземпляр PDO, вызовет фатальную ошибку.
Пример 6: Ограничение доступа через .user.ini в подкаталогах
Создайте файл .user.ini в каталоге /var/www/private:
; /var/www/private/.user.ini
open_basedir = "/var/www/private"
disable_functions = exec, system, ini_set
Результат: все PHP-скрипты внутри private будут видеть только свою директорию и не смогут менять настройки через ini_set.
Пример 7: Комплексная блокировка через mod_rewrite в Apache
Перенаправлять все запросы к .php на статическую страницу, но разрешить только index.php:
RewriteEngine On
RewriteCond %{REQUEST_URI} \.php$
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule .* /forbidden.html [R=403,L]
Результат: любой запрос к любому PHP-файлу, кроме index.php, будет перенаправлен на 403.
Пример 8: Использование PHP-FPM pool с ограничениями
В конфигурации пула PHP-FPM можно установить лимиты на ресурсы и заблокировать некоторые функции через php_admin_value:
[secured]
user = www-data
group = www-data
pm = dynamic
pm.max_children = 5
php_admin_value[disable_functions] = exec,system
php_admin_value[open_basedir] = /var/www/secured
Результат: все скрипты в этом пуле работают с ограниченными правами, не могут выполнять системные команды и видят только свою директорию.
Пример 9: Блокировка через .htaccess с использованием mod_authz_core (Apache 2.4+)
<FilesMatch \.php$>
Require all denied
</FilesMatch>
Результат: все PHP-файлы закрыты. Чтобы открыть конкретный файл, используйте <Files "file.php"> Require all granted </Files>.
Пример 10: Проверка конфигурации после изменений
Для проверки, какие директивы включены, создайте скрипт info.php с phpinfo() и временно разместите в тестовом каталоге. После тестов удалите.
<?php phpinfo(); ?>
Посмотрите раздел Configuration File (php.ini) Path и disable_functions.