Защита файлового менеджера PHP от его пользователей
-
03-07-2019 - |
Вопрос
Всем привет, я разрабатываю веб-сайт для обмена фотографиями, используя PHP-фреймворк CodeIgniter.Идея заключается в том, что люди могли бы загружать свои фотографии, управлять ими (через какой-нибудь файловый браузер, который позволяет им создавать вложенные папки, перетаскивать файлы и т.д.) И редактировать их (для начала некоторые базовые вещи, такие как изменение размера, поворот и обрезка, а позже я добавлю некоторые расширенные функции).
Я уже внедрил стороннее решение для аутентификации для CI (Повторная аутентификация 2 Бета-версии) и сейчас я интегрирую файловый менеджер JS / PHP (AjaxExplorer), но проблема в том, что серверная часть PHP для управления файлами (перемещение, копирование и т.д.) Слишком сильно доверяет пользовательскому вводу из вызовов ajax.Например, он делает такие вещи, как это (упрощено для большей ясности):
move_uploaded_file($_FILES['upload']['tmp_name'], $root.$username.$_POST['destination_dir']);
Как вы можете видеть, существуют очевидные проблемы с безопасностью, поскольку он слепо принимает любой путь, который вводит пользователь!Я уже вижу, что кто-то отправляет что-то вроде "../AnotherUser/" в качестве значения $_POST['destination_dir'].
Мой вопрос заключается в следующем: Каков наилучший способ "изолировать" пользователя, чтобы позволить ему управлять только своими собственными данными? Должен ли я просто проверять + фильтровать входные данные, надеясь перехватить каждую попытку вторжения?Существуют ли какие-либо библиотеки / пакеты, предназначенные для решения этой конкретной проблемы?
Я думаю, что эта проблема должна быть каким-то образом решена в любом (достаточно зрелом) проекте, который дает своим пользователям возможность управлять своими файлами через веб-браузер, поэтому я ожидал найти какие-то четкие рекомендации по этому поводу (поскольку там много о SQL-инъекциях, XSS, CSRF и т.д.), Но, думаю, я использую не те ключевые слова.
Решение
Каков наилучший способ "изолировать" пользователя, чтобы позволить ему управлять только своими собственными данными?
Разрешайте любые имена файлов / каталогов по желанию пользователя, но просто не используйте их в файловой системе на стороне сервера.Вместо этого запишите имена путей в базу данных с первичным ключом и используйте первичный ключ как имя файла, например ‘34256.dat’, в плоском каталоге хранения (или даже как большой двоичный объект в базе данных, если хотите).Затем выполните загрузку с помощью скрипта загрузки или перепишите URL-адрес, чтобы в URL-адресе отображалось желаемое имя файла.
Очистка входящих имен файлов - это жесткий.Обнаружение ‘..’ - это только начало.Слишком длинные имена файлов;слишком короткие имена файлов;комбинации начальных и завершающих точек;комбинации начальных и завершающих пробелов;различные разделители каталогов для разных платформ;символы, которые недопустимы на некоторых платформах;управляющие символы;Символы Юникода и способы обращения к ним в зависимости от среды;ADSs;имена файлов (‘.htaccess’) или расширения (‘.php’, ‘.cgi’), которые могут быть ‘особенными’ для вашего веб-сервера;Зарезервированные имена файлов Windows...
Вы можете потратить всю жизнь, выслеживая забавные маленькие причуды правил пути к файлам на различных платформах, или вы можете просто забыть об этом и использовать базу данных.
Другие советы
Я не уверен, что ваш destination_dir
похоже, но то, о чем я думал, - это присвоение ключей каталогов, а затем получение каталога на основе этого ключа.Например:
//$_POST['destination_dir'] = '4hg43h5g453j45b3';
*_query('SELECT dir FROM destinations WHERE key = ? LIMIT 1'); //etc.
Однако вы должны заранее определить ключи перед раздачей.Другой альтернативой могло бы быть обратное:md5 / sha1 введите и используйте это как destination_dir , затем сохраните этот ключ в базе данных с соответствующей меткой.
Насколько мне известно, нет ни одной библиотеки.
Однако в вашем конкретном примере удалите все (обратные) косые черты и точки из строки, а затем добавьте косую черту в ее конец, чтобы пользователь не мог изменять папки.
$destdir = str_replace(array('.', '/', '\\'), '', $_POST['destination_dir']);
$destdir .= "/";