Я читал о безопасности загрузки файлов PHP, и несколько статей рекомендовали переименовать файлы. Например, в статье OWASP « Неограниченная загрузка файлов» говорится:
Для определения имен файлов рекомендуется использовать алгоритм. Например, имя файла может быть хэшем MD5 имени файла плюс дата дня.
- Вход защищен PHP
- где безопасность в PHP 5.4, удалив safe_mode
- PHP session var достаточно для пользователя auth?
- Как динамически управлять ролями | разрешениями в Symfony2: ограничить функции динамическими ролями
- json_decode возвращает NULL в строке, прошедшей через шифрование
- Каков наилучший способ реализации двухстороннего шифрования с помощью PHP?
Если пользователь загружает файл с именем Cake Recipe.doc
действительно ли есть какая-то причина переименовать его в 45706365b7d5b1f35
?
Если ответ «да», по какой-либо причине, то как вы отслеживаете исходное имя файла и расширение?
На ваш основной вопрос, правильно ли переименовывать файлы, ответ – это определенное да, особенно если вы создаете форму Файлового репозитория, где пользователи загружают файлы (и имена файлов) по своему выбору по нескольким причинам:
Cake Recipe.doc
не является безопасным именем URL и может на некоторых системах (на стороне сервера или браузера) / в некоторых ситуациях вызвать несоответствия, когда имя должно быть значением urlencode
d. Что касается хранения информации, вы, как правило, делаете это в базе данных, ничем не отличающейся от той, что у вас уже есть, поскольку вам нужен способ вернуться к файлу (кто загрузил, какое имя, время от времени, где он хранится, время загрузки, иногда размер). Вы просто добавляете к этому фактическое сохраненное имя файла в дополнение к имени пользователя для файла.
Рекомендация OWASP не является плохим – использование имени файла и отметки времени (не даты) будут в основном уникальными. Я делаю еще один шаг, чтобы включить микросессию с меткой времени и часто некоторые другие уникальные бит информации, так что дублирование загрузки небольшого файла не может происходить в один и тот же таймфрейм – я также сохраняю дату загрузки что является дополнительной страховкой против столкновений md5, которая имеет более высокую вероятность в системах, которые хранят много файлов и в течение многих лет. Это невероятно маловероятно, что в тот же день вы создадите два типа md5, используя имя файла и microtime. Примером может служить:
$filename = date('Ymd') . '_' . md5($uploaded_filename . microtime());
Мои 2 цента.
Когда я загружаю файлы, я использую функцию unique_id () PHP для имени файла, которое хранится на сервере (и я сохраняю расширение файла, так как это облегчает мне, когда я просматриваю все файлы в каталоге хранилища через локальный файл система).
Я сохраняю файл за пределами файловой системы сайта (иначе вы никогда не сможете напрямую просматривать файлы).
Я всегда использую функцию move_uploaded_file () php для сохранения файла на сервере.
Я сохраняю исходное имя файла, путь / имя файла, в котором он хранится, и любую другую связанную с проектом информацию, которая может потребоваться о том, кто ее загрузил и т. Д. В базе данных.
В некоторых моих реализациях я также создаю хэш содержимого файла и сохраняю его в базе данных. Затем с другими загруженными файлами посмотрите в базе данных, чтобы увидеть, есть ли у меня копия этого точного файла, который уже сохранен.
Некоторые примеры кода:
Форма:
form method="post" enctype="multipart/form-data" action="your_form_handler.php"> <input type="file" name="file1" value="" /> <input type="submit" name="b1" value="Upload File" /> </form>
Обработчик формы:
<?php // pass the file input name used in the form and any other pertinent info to store in the db, username in this example _process_uploaded_file('file1', 'jsmith'); exit; function _process_uploaded_file($file_key, $username='guest'){ if(array_key_exists($file_key, $_FILES)){ $file = $_FILES[$file_key]; if($file['size'] > 0){ $data_storage_path = '/path/to/file/storage/directory/'; $original_filename = $file['name']; $file_basename = substr($original_filename, 0, strripos($original_filename, '.')); // strip extention $file_ext = substr($original_filename, strripos($original_filename, '.')); $file_md5_hash = md5_file($file['tmp_name']); $stored_filename = uniqid(); $stored_filename .= $file_ext; if(! move_uploaded_file($file['tmp_name'], $data_storage_path.$stored_filename)){ // unable to move, check error_log for details return 0; } // insert a record into your db using your own mechanism ... // $statement = "INSERT into yourtable (original_filename, stored_filename, file_md5_hash, username, activity_date) VALUES (?, ?, ?, ?, NOW())"; // success, all done return 1; } } return 0; } ?>
Программа для обработки запросов на скачивание
<?php // Do all neccessary security checks etc to make sure the user is allowed to download the file, etc.. // $file = '/path/to/your/storage/directory' . 'the_stored_filename'; $filesize = filesize($file); header('Content-Description: File Transfer'); header("Content-type: application/forcedownload"); header("Content-disposition: attachment; filename=\"filename_to_display.example\""); header("Content-Transfer-Encoding: Binary"); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header("Content-length: ".$filesize); ob_clean(); flush(); readfile("$file"); exit;
Если вы хотите представить загрузку на той же странице, на которую пользователь запрашивает ее, посмотрите на мой ответ на этот пост: Загрузите несколько файлов PDF из javascript
Существует хорошая причина, по которой вам нужно переименовать загруженный файл, и это, если два загружают один и тот же файл или файлы с тем же именем, последний файл заменит прежний файл, который не является благоприятным.
вы можете использовать хэширующие альгоны, такие как
$extensions = explode(".",$file-name); $ext = $extensions[count($extensions)-1]; $file-name = md5($file-name .$_SERVER['REMOTE_ADDR']) .'.' .$ext;
то вы можете сохранить данные о имени файла, хэшированном имени файла, сведения о загрузчике, дате, времени, чтобы отслеживать файлы