Следует ли переименовать загруженные файлы?

Я читал о безопасности загрузки файлов PHP, и несколько статей рекомендовали переименовать файлы. Например, в статье OWASP « Неограниченная загрузка файлов» говорится:

Для определения имен файлов рекомендуется использовать алгоритм. Например, имя файла может быть хэшем MD5 имени файла плюс дата дня.

Если пользователь загружает файл с именем Cake Recipe.doc действительно ли есть какая-то причина переименовать его в 45706365b7d5b1f35 ?

Если ответ «да», по какой-либо причине, то как вы отслеживаете исходное имя файла и расширение?

Solutions Collecting From Web of "Следует ли переименовать загруженные файлы?"

На ваш основной вопрос, правильно ли переименовывать файлы, ответ – это определенное да, особенно если вы создаете форму Файлового репозитория, где пользователи загружают файлы (и имена файлов) по своему выбору по нескольким причинам:

  1. Безопасность – если у вас плохо написанное приложение, которое позволяет загружать файлы по имени или через прямой доступ (это ужасно, но это происходит), пользователю гораздо труднее, злонамеренно или специально, «угадать» имена файлов.
  2. Уникальность – вероятность того, что два разных пользователя загружают файл с таким же именем, очень высок (например, аватар.gif, readme.txt, video.avi и т. Д.). Использование уникального идентификатора значительно снижает вероятность того, что два файла будут иметь одинаковое имя.
  3. Версии – намного проще хранить несколько «версий» документа с использованием уникальных имен. Он также избегает необходимости в дополнительном коде для анализа имени файла для внесения изменений. Простым примером может быть document.pdf для документа (1) .pdf, который становится более сложным, если вы не недооцениваете возможности пользователей создавать ужасные имена для вещей.
  4. Длина – работа с известными длинами имен файлов всегда лучше, чем работа с неизвестными длинами имен файлов. Я всегда могу знать, что (мой путь к файлу) + (буквы X) является определенной длиной, где (мой путь к файлу) + (случайное имя пользователя пользователя) полностью неизвестно.
  5. OS – вышеописанная длина также может создавать проблемы при попытке записать на диск чрезвычайно случайные / длинные имена файлов. Вы должны учитывать специальные символы, длины и проблемы для обрезанных имен файлов (пользователь может не получить рабочий файл, потому что расширение было обрезано).
  6. Выполнение. ОС легко выполнить файл с именем .exe или .php или (вставить другое расширение). Это трудно, если нет расширения.
  7. URL-кодирование. Обеспечение безопасного URL-адреса. 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; 

то вы можете сохранить данные о имени файла, хэшированном имени файла, сведения о загрузчике, дате, времени, чтобы отслеживать файлы