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

#php

#php

Вопрос:

Я написал php-скрипт, который проверяет файл изображения на его расширение, такое как JPG, JPEG, PNG, GIF, загруженный через HTML-форму.

Теперь возникает моя проблема: любой может загрузить файл любого типа, присвоив ему расширение JPG, JPEG, PNG, GIF.

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

Я очень старался… но не удалось… Вот написанный мной php-скрипт ПРОВЕРЬТЕ мой ПОЛНЫЙ КОД, который я НАПИСАЛ, И ОН РАБОТАЕТ НОРМАЛЬНО, НО КОГДА я МЕНЯЮ РАСШИРЕНИЕ ЛЮБОГО ФАЙЛА На РАСШИРЕНИЕ ИЗОБРАЖЕНИЯ, РАЗРЕШАЮЩЕЕ ЗАГРУЗКУ На СЕРВЕР, КОТОРЫЙ НЕ ЯВЛЯЕТСЯ SERCURE ПОЖАЛУЙСТА, ПОСМОТРИТЕ этот ПОЛНЫЙ КОД И ДОБАВЬТЕ РЕШЕНИЕ, ЭТО ТОЖЕ ПОМОЖЕТ ДРУГИМ — СПАСИБО https://www.dropbox.com/s/prza75dyo7usjqy/secure image upload with checking extension.txt?dl=0

 if (isset($_POST['submit']))

    $filename = $_FILES["file"]["name"];
    $file_basename = substr($filename, 0, strripos($filename, '.')); // get file extention
    $file_ext = substr($filename, strripos($filename, '.')); // get file name
    $filesize = $_FILES["file"]["size"];
    $allowed_file_types = array('.jpg','.png','.jpeg','.gif');  
    
    //instead of allowed file type i want to check image authenticity with MIME

    if (in_array($file_ext,$allowed_file_types) amp;amp; ($filesize < 100000))
    
  
  

Ответ №1:

Вам следует использовать fileinfo API, который позволяет вам проверять тип содержимого файла MIME, просматривая его байты, а не его имя.

Тип MIME изображения всегда начинается с image/ , например image/png .

 $finfo = new finfo();
$mimeType = $finfo->file($_FILES['file']['tmp_name'], FILEINFO_MIME_TYPE);

$isImage = strpos($mimeType, 'image/') === 0;
  

Если вы хотите строго ограничить разрешенные изображения, проверьте список доступных типов MIME.

Редактировать: быть более конкретным

 if (isset($_POST['submit'])) {
    $filename = $_FILES["file"]["tmp_name"];
    $filesize = $_FILES["file"]["size"];
    $allowed_file_types = array('image/jpeg','image/png','image/gif');
    $finfo = new finfo();
    $mimeType = $finfo->file($filename, FILEINFO_MIME_TYPE);
    $isImage = in_array($mimeType, $allowed_file_types);

    if ($isImage amp;amp; $filesize < 100000) {
  

Комментарии:

1. Пожалуйста, ответьте в контексте приведенного выше кода, как я могу применить этот код к верхнему, пожалуйста, укажите

2. Я отредактировал его. Обратите внимание, что я использую tmp_name ключ для извлечения имени файла на стороне сервера, а не name на стороне клиента.

3. сэр, не работает, проверьте мой полный код и добавьте к нему решение dropbox.com/s/prza75dyo7usjqy /…

4. надеюсь, ты шутишь, приятель 🙂 я здесь не для того, чтобы выполнять твою работу. Этот фрагмент кода работает , даже если вы говорите, что это не так. Помните, когда вы просили меня указать ?

Ответ №2:

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

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

Такие расширения, как fileinfo , проверяют маркер только в первых нескольких байтах, но это не на 100% надежно. Для вас этого может быть достаточно

Комментарии:

1. Я колебался между моим текущим ответом и другим, похожим на ваши шаги, с Imagick API, но поскольку мне кажется, что это вопрос для начинающих и учитывая крошечный размер fileinfo по сравнению с Imagick , я выбрал fileinfo .

2. @rugolinifr да, я подумал, что это хороший вопрос, на который может быть 2 правильных ответа =)