2013-07-25 4 views
3

Я читал о безопасности загрузки файлов PHP, и несколько статей рекомендовали переименовать файлы. Например, OWASP статья Unrestricted File Upload говорит:Следует ли переименовать загруженные файлы?

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

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

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

+3

обычно отслеживать файлы, помещая путь и информацию о файле в таблицу базы данных. Что касается переименования, я только сделал переименование, чтобы убедиться, что имена файлов совместимы с ОС. Например, 'Cake Recipe.doc' имеет место в нем, linux действительно не любит разделенные имена файлов на линии commmand, поэтому, если вам нужно выполнить функции командной строки в файле, вам придется обернуть его в правильные кавычки, если вы не переименовали Это. –

+1

Вы можете сохранить исходное имя и расширение в базе данных вместе с новым именем во время загрузки –

+2

, подумайте о плохо разработанной системе, которая позволила бы кому-то загружать файлы '.php'.Если вы поместите файлы с предоставленным именем пользователя в корневой каталог вашего сайта, этот пользователь может теперь ПОЛНОСТЬЮ взять на себя ваш сервер, потому что они могут загружать и EXECUTE произвольный код на вашем сервере. –

ответ

11

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

  1. безопасности - если у вас есть плохо письменное заявление, что позволяет загружать файлы по имени или через прямой доступ (это ужасно, но это происходит), это m намного сложнее для пользователя, злонамеренно или намеренно, «угадать» имена файлов.
  2. Уникальность - вероятность двух разных пользователей, загружающих файл с таким же именем, очень высока (например, аватар.gif, readme.txt, видео.avi и т. д.). Использование уникального идентификатора значительно снижает вероятность того, что два файла будут иметь одинаковое имя.
  3. Версии - намного проще хранить несколько «версий» документа с использованием уникальных имен. Он также избегает необходимости в дополнительном коде для анализа имени файла для внесения изменений. Простым примером может быть document.pdf для документа (1) .pdf, который становится более сложным, если вы не недооцениваете возможности пользователей создавать ужасные имена для вещей.
  4. Длина - работа с известными длинами имен файлов всегда лучше, чем работа с неизвестными длинами имен файлов. Я всегда могу знать, что (мой путь к файлу) + (буквы X) является определенной длиной, где (мой путь к файлу) + (случайное имя пользователя пользователя) полностью неизвестно.
  5. ОС - вышеописанная длина также может создавать проблемы при попытке записать чрезвычайно случайные/длинные имена файлов на диск. Вы должны учитывать специальные символы, длины и проблемы для обрезанных имен файлов (пользователь может не получить рабочий файл, потому что расширение было обрезано).
  6. Выполнение - ОС легко выполнить файл с именем .exe или .php или (вставить другое расширение). Это трудно, если нет расширения.
  7. URL-кодирование - обеспечение безопасного URL-адреса. Cake Recipe.doc не является безопасным именем URL и может на некоторых системах (на стороне сервера или браузера)/в некоторых ситуациях вызвать несоответствия, когда имя должно быть значением urlencode d.

Что касается хранения информации, вы обычно делаете это в базе данных, отличной от той, которая вам нужна, поскольку вам нужен способ вернуться к файлу (кто загрузил, какое имя, иногда там, где он хранится, время загрузки, иногда размер). Вы просто добавляете к этому фактическое сохраненное имя файла в дополнение к имени пользователя для файла.

Рекомендация OWASP не является плохим - использование имени файла и отметки времени (а не даты) будут в основном уникальными. Я делаю еще один шаг, чтобы включить микросессию с меткой времени и часто некоторые другие уникальные бит информации, так что дублирование загрузки небольшого файла не может происходить в один и тот же таймфрейм - я также сохраняю дату загрузки что является дополнительной страховкой против столкновений md5, которая имеет более высокую вероятность в системах, которые хранят много файлов и в течение многих лет. Это невероятно маловероятно, что в тот же день вы создадите два типа md5, используя имя файла и microtime. Примером может служить:

$filename = date('Ymd') . '_' . md5($uploaded_filename . microtime()); 

Мои 2 цента.

+0

Действительно отличный ответ, спасибо! – Nate

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; 

Если вы хотите представить загрузку в одной и той же странице, что пользователь запрашивает его из затем посмотрите на мой ответ на этот пост: Dowloading multiple PDF files from javascript

+0

Спасибо за пример кода! – Nate

1

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

вы можете использовать хеширование Algos как

$extensions = explode(".",$file-name); 
$ext = $extensions[count($extensions)-1]; 
$file-name = md5($file-name .$_SERVER['REMOTE_ADDR']) .'.' .$ext; 

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

Смежные вопросы