Загрузка файлов и open_basedir: почему надо пользоваться стандартными функциями
Казалось бы вопрос загрузки файлов на сервер обсосан до косточек, но одно недавнее событие заставило меня в этом усомниться.
Некоторое время назад в целях повышения безопасности на наших серверах была включена настройка PHP open_basedir. После этого многие PHP-приложения перестали загружать файлы на сервер.
- open_basedir ограничивает список файлов, к которым может обращаться PHP, указанным деревом директорий.
- open_basedir может применяться независимо от того, используется защищенный режим или нет.
Конечно же язык PHP разрабатывают неглупые люди, поэтому действие open_basedir не распространяется на функции is_uploaded_file и move_uploaded_file, которые, собственно, и предназначены для работы с загруженными файлами.
Так в чём же тогда проблема? А проблема вот в чём: многие (действительно многие!) обращаются к загруженным файлам именно напрямую, в обход стандартных функций.
Обычно это делается в тех случаях, когда загруженный файл не предполагается хранить на сайте. Как правило это импорт прайс-листов (csv, xls), картинки, которые конвертируются перед сохранением в дереве файлов сайта. Часто $_FILES используется для проверки загруженной картинки (getimagesize) перед вызовом move_uploded_file.
Я настоятельно советую PHP-программистам (особенно начинающим), во-первых, не пренебрегать использованием стандартных функций. Если функцию написали, значит она для чего-то нужна. Во-вторых, хорошенько изучить настройки PHP и режимы его работы. Это поможет избежать таких вот ошибок.
P. S. Кто-то может сказать «нефиг так конфигурировать сервера, что скрипты перестают работать». Однако я считаю, что если настройка есть, то кто-нибудь её обязательно использует. И если ваша программа после этого перестанет работать, то камни полетят в вас. Оно вам (нам) надо?
- php
- upload
- загрузка файлов
- open_basedir
- move_uploaded_file
- is_uploaded_file
Для чего нужна и как использовать open_basedir
Директива open_basedir указывается в конфигурационном файле PHP (php.ini) и устанавливает директории, к которым может иметь доступ PHP. Под доступом понимаются любые действия с файлами: открытие (например, функции fopen() или gzopen()), записи и выполнения. Если директива open_basedir установлена и делается попытка запустить файл, который находится за пределами перечисленных директорий, то скрипт не запустится и выдаст ошибку:
[Wed Apr 1 13:11:34 2020] PHP Warning: Unknown: open_basedir restriction in effect. File(/usr/share/seeker/template/nearyou/php/info.php) is not within the allowed path(s): (/srv/http/:/etc/webapps/:/usr/share/webapps/:/tmp/:/home/mial/) in Unknown on line 0
Пример значения open_basedir:
open_basedir = /srv/http/:/etc/webapps/:/usr/share/webapps/:/tmp/:/home/mial/
В указанном примере разрешён запуск скриптов PHP, а также операции с файлами в директориях:
- /srv/http/
- /etc/webapps/
- /usr/share/webapps/
- /tmp/
- /home/mial/
Директива open_basedir оказывает влияние на многие функции. Больше всего в ней смысла при использовании на уровне конфигурационных файлов веб-сервера на уровне директорий или виртуальных хостов.
По умолчанию, если значение open_basedir не установлено, разрешены файловые операции в любых директориях компьютера (на которые достаточно прав).
Опция open_basedir может распространяться не только на функции для работы с файловой системой; например, если MySQL настроен использовать драйвер mysqlnd, то LOAD DATA INFILE подпадает под опцию open_basedir . Множество функций PHP также использует open_basedir.
Специальное значение . (точка) обозначает, что рабочая директория скрипта будет использована в качестве базовой директории. Однако, это немного опасно, так как текущая директория скрипта может быть легко изменена с помощью chdir().
В httpd.conf, open_basedir может быть выключена (например, для некоторых виртуальных хостов) тем же способом, что и любая другая конфигурационная директива:
php_admin_value open_basedir none
В Windows разделяйте директории символом ; (точкой с запятой). На всех остальных системах, разделяйте директории символом : (двоеточием). При работе в качестве модуля Apache, пути open_basedir автоматически наследуются от родительских директорий.
Связанные статьи:
- Что делать если PHP скрипту не хватает времени и памяти. Почему большой файл не загружается на сайт или в phpMyAdmin (100%)
- Почему не работают короткие теги в PHP (100%)
- Как изменить количество цифр после запятой в PHP. Как увеличить точность вычислений в PHP (100%)
- Как и какие функции отключить в PHP (100%)
- Как установить веб-сервер Apache с PHP, MySQL и phpMyAdmin на Windows (100%)
- Как сбросить пароль root MySQL или MariaDB в Windows (RANDOM — 50%)
Нужен хостинг с защитой от шелов и прочего
>> Как сказал smart2web только через open_basedir. Я не буду с Вами спорить, но open_basedir абсолютно бесполезная штука, не кто не мешает вызвать любую функцию из семейства exec и запустить отдельный процесс без open_basedir, при этом не обязательно на php. Можно запретить половину функций, но часть CMS при этом точно перестанет работать.
— С Уважением Алексей Маникин.
На сайте с 30.12.2015
24 марта 2017, 13:02
alexeyymanikin:
>> Как сказал smart2web только через open_basedir.
Я не буду с Вами спорить, но open_basedir абсолютно бесполезная штука, не кто не мешает вызвать любую функцию из семейства exec и запустить отдельный процесс без open_basedir, при этом не обязательно на php.
Можно запретить половину функций, но часть CMS при этом точно перестанет работать.
Ну тогда по разным дата-центрам разносить сайты, чего уж там. Интересно, какая CMS работает с функцией exec и еще интересно, почему мы не рассматриваем php как модуль апач? Какие еще отдельные процессы?
На сайте с 20.09.2008
24 марта 2017, 13:25
smart2web:
Ну тогда по разным дата-центрам разносить сайты, чего уж там.
Интересно, какая CMS работает с функцией exec и еще интересно, почему мы не рассматриваем php как модуль апач? Какие еще отдельные процессы?
То есть предполагается выключать функции exec ? Насколько я знаю у Bitrix долгие операции реализованы в том числе через exec (хотя могу ошибаться). Так же бывает нужно вызывать ffmpeg, curl — года 3-4 назад мы собирали статистику по вызовам этих функций и как не странно они используются. Мы как раз и рассматриваем php как модуль apache, но при этом он работает из под разных пользователей. Но тут проблема даже не в PHP. Ок может пользователь будет использовать python, node.js или perl не дай бог. То есть данный вопрос надо решать комплексно, не на уровне отдельно взятого языка с его костылями — а на уровне операционной системы.
>> Какие еще отдельные процессы? Не могу не задать вопрос — а как по вашему работает php как модуль apache ? Обрабатывает все запросы в рамках одного процесса ? =) Или же все таки apache, например создает несколько потомков — передает им обработку запроса, далее в зависимости от сайта потомок суидится в пользователя и уже потом вызывает php в рамках своего процесса для обработки запроса =)
На сайте с 30.12.2015
24 марта 2017, 13:30
alexeyymanikin:
Не могу не задать вопрос — а как по вашему работает php как модуль apache ? Обрабатывает все запросы в рамках одного процесса ? =) Или же все таки apache, например создает несколько потомков — передает им обработку запроса, далее в зависимости от сайта потомок суидится в пользователя и уже потом вызывает php в рамках своего процесса для обработки запроса =)
Согласен, но open_basedir не даст такому процессу попасть выше указанного значения.
На сайте с 20.09.2008
24 марта 2017, 13:38
smart2web:
Согласен, но open_basedir не даст такому процессу попасть выше указанного значения.
Вы мои сообщения читаете ? Это только в том случае если у ваз заблокированы все функции аля exec — что фактически причиняет боль пользователям. И это работает только в случае PHP. А если посмотреть более внимательно http://php.net/manual/ru/ini.core.php open_basedir изменяется PHP_INI_ALL после версии 5.3 что означает http://php.net/manual/ru/configuration.changes.modes.php «Значение может быть установлено отовсюду» — ну кто мешает получив доступ к файлу, изменить .htaccess ? При этом Вы продолжаете уверять меня, что open_basedir защитит сайты пользователей ?
На сайте с 04.01.2012
24 марта 2017, 14:06
Почему наши коллеги не водят подобную или другую систему изоляции для меня до сих пор остается загадкой, так как принцип работы нашей системы я уже описывал не раз.
Алексей, поделитесь пожалуйста ссылочкой, где можно почитать?
NVMe VDS (https://well-web.net/nvme-vps) с поддержкой 24/7 — от 545 руб.! Безлимитный хостинг (https://well-web.net/ssd-hosting) — от 129 руб.! Домен в подарок! Перенос бесплатно! Заказывайте сейчас, и получите скидку 50%! Заходи! (https://well-web.net/limited-offers)
На сайте с 05.06.2007
24 марта 2017, 15:38
Действительно, open_basedir теперь можно менять везде, но практика показывает что вирусня пока не догадывается до отмены open_basedir и заражается обычно только тот сайт который дырявый, возможно ей этого достаточно. Лучше всего не использовать всякие дырявые системы, вовремя обновлять CMS, ну и на крайний случай действительно раскидывать по аккаунтам где уже будет 100%я изоляции. PS> Про систему изоляции бегета хотелось бы тоже почитать, а пока не понятно о чём там речь.
Написал не мало шедевров 😉
На сайте с 26.06.2010
24 марта 2017, 17:48
open_basedir вообще не поможет, нужно изолировать на уровне пользователей. а отключение функций в php это костыли которые только мешают.
На сайте с 09.12.2005
24 марта 2017, 18:40
Dimanych:
Действительно, open_basedir теперь можно менять везде, но практика показывает что вирусня пока не догадывается до отмены open_basedir и заражается обычно только тот сайт который дырявый, возможно ей этого достаточно. Лучше всего не использовать всякие дырявые системы, вовремя обновлять CMS, ну и на крайний случай действительно раскидывать по аккаунтам где уже будет 100%я изоляции.
Зря Вы так думаете, есть и такие, которые не только заражают соседние сайты пользователя, но и например заливают скомпилированную прогу в общедоступную директорию и шлют СПАМ! open_basedir вообще лишний параметр, который только тормозит работу сайтов и ни как не помогает.
MGNHost.ru — полный комплекс хостинг услуг ( https://www.mgnhost.ru ) VPS/VDS на SSD дисках в России / Нидерландах / США от 210 рублей ( https://www.mgnhost.ru/vds.php )
На сайте с 30.12.2015
24 марта 2017, 18:50
globalmoney:
Зря Вы так думаете, есть и такие, которые не только заражают соседние сайты пользователя, но и например заливают скомпилированную прогу в общедоступную директорию и шлют СПАМ!
open_basedir вообще лишний параметр, который только тормозит работу сайтов и ни как не помогает.
Речь не обезопасить сайты в целом от взлома. ТС прекрасно понимает, что это вполне возможно, а разделить, что бы один сайт не заразил другой, а с basedir это в принципе достигается при должных настройках сервера.
Настройка open_basedir на примере VestaCP
В некоторых панелях управления сервером, например VestaCP по-умолчанию директива open_basedir настроена только на запуск php-скриптов внутри директории public_html у домена. Но т.к. ради безопасности нам необходимо разместить файлы проекта выше www, то open_basedir необходимо перенастроить. В противном случае, мы постоянно будем получать ошибку вида File . is not within the allowed path(s).
Можно поменять настройку в основном php.ini распрстранив, таким образом, изменения на весь сервер. Если вы забыли где лежит файл конфигурации то воспользуйтесь командой
$ php -i | grep php.ini
Допустим, нас интересует решение для конкретного домена, а не сервера целиком. На форуме весты есть такое решение: создайте в дополнительный конфигурационный файл /home/%user%/conf/web/httpd.%domain%.conf в котором будет прописано:
php_admin_value open_basedir none
Но полностью отключать настройку не всегда безопасно, к тому же, если присмотреться, то в директории /home/%user%/conf/web/ можно найти файл apache2.conf
Открываем его, например, с помощью nano (не забывайте добавлять папаметр -w при открытии конфигурационных файлов)
nano -w home/user/conf/web/apache2.conf
В нём в разделе Directory есть строчка вида
php_admin_value open_basedir /home/user/web/domain/public_html:/home/user/tmp
Здесь указано 2 разрешённых пути, двоеточие — это разделитель между ними. Например, мы хотим разрешить выполнение php в папке project на один уровень выше веб-директории public_html, тогда добавляем в конце строки:
:/home/user/web/domain/project
Сохраняем изменения Ctrl+O, выходим Ctrl+X. Теперь перезапустим апач что бы новые настройки вступили в силу:
etc/init.d/apache2 restart
Всё готово, если что-то не работает ищите опечатку.