Каков наиболее безопасный способ для загрузки файла?

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

Я пытаюсь настроить серию сценариев загрузки «plug-and-play-type» для использования внутри компании, которые дизайнер может скопировать в структуру своего сайта, изменить несколько переменных и иметь готовые к отправке формы на их сайт. Мы стремимся максимально ограничить нашу экспозицию (мы уже закрыли команды fopen и shell).

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

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

Solutions Collecting From Web of "Каков наиболее безопасный способ для загрузки файла?"

Лучшим решением, IMHO, является размещение каталога, содержащего загруженные файлы вне «веб-среды», и использование сценария для их загрузки. Таким образом, даже если кто-то загружает скрипт, он не может быть выполнен, вызывая его из браузера, и вам не нужно проверять тип загружаемого файла.

  1. Разрешить только авторизованным пользователям загружать файл. Вы можете добавить капчу, чтобы помешать примитивным ботам.

  2. Прежде всего, установите MAX_FILE_SIZE в вашей форме загрузки и установите максимальный size файла и count на сервере .

     ini_set('post_max_size', '40M'); //or bigger by multiple files ini_set('upload_max_filesize', '40M'); ini_set('max_file_uploads', 10); 

    Проверьте размер загруженных файлов:

     if ($fileInput['size'] > $sizeLimit) ; //handle size error here 
  3. Вы должны использовать $_FILES и move_uploaded_file() чтобы поместить ваши загруженные файлы в нужный каталог или если вы хотите обработать его, а затем is_uploaded_file() флажок is_uploaded_file() . (Эти функции существуют для предотвращения инъекций имени файла, вызванных register_globals .)

     $uploadStoragePath = '/file_storage'; $fileInput = $_FILES['image']; if (fileInput['error'] != UPLOAD_ERR_OK) ; //handle upload error here //size check here $temporaryName = $fileInput['tmp_name']; $extension = pathinfo($fileInput['name'], PATHINFO_EXTENSION); //mime check, chmod, etc. here $name = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //true random id move_uploaded_file($temporaryName, $uploadStoragePath.'/'.$name.'.'.$extension); 

    Всегда создавайте случайный идентификатор вместо использования исходного имени файла .

  4. Создайте новый поддомен, например http://static.example.com или по крайней мере новый каталог за пределами public_html , для загруженных файлов. Этот поддомен или каталог не должен выполнять какой-либо файл . Установите его в конфигурацию сервера или установите в файле .htaccess каталог.

      SetHandler none SetHandler default-handler Options -ExecCGI php_flag engine off 

    Установите его также с помощью chmod() .

      $noExecMode = 0644; chmod($uploadedFile, $noExecMode); 

    Используйте chmod() для недавно загруженных файлов и установите его в каталоге.

  5. Вы должны проверить тип mime, отправленный хакером. Вы должны создать белый список допустимых типов mime . Разрешать изображения только в том случае, если какой-либо другой формат не требуется. Любой другой формат представляет собой угрозу безопасности. Изображения тоже, но по крайней мере у нас есть инструменты для их обработки …
    Например, поврежденный контент : HTML в файле изображения может вызвать XSS браузерами с уязвимостью, снижающей уровень содержимого . Когда поврежденный контент является PHP- кодом, его можно комбинировать с уязвимостью, вызванной eval injection .

     $userContent = '../uploads/malicious.jpg'; include('includes/'.$userContent); 

    Попытайтесь избежать этого, например, используйте class autoloader а не вручную вставляйте файлы php …
    Обрабатывая javascript-инъекцию сначала, вы должны отключить xss и контент, обнюхивающий в браузерах . Проблемы с обнюханием контента типичны для старых msie , я думаю, что другие браузеры фильтруют их довольно хорошо. В любом случае вы можете предотвратить эти проблемы с кучей заголовков. (Не поддерживается всеми браузерами, но это лучшее, что вы можете сделать на стороне клиента.)

     Strict-Transport-Security: max-age={your-max-age} X-Content-Type-Options: nosniff X-Frame-Options: deny X-XSS-Protection: 1; mode=block Content-Security-Policy: {your-security-policy} 

    Вы можете проверить, поврежден ли файл с Imagick identify , но это не означает полную защиту.

     try { $uploadedImage = new Imagick($uploadedFile); $attributes = $uploadedImage->identifyImage(); $format = $image->getImageFormat(); var_dump($attributes, $format); } catch (ImagickException $exception) { //handle damaged or corrupted images } 

    Если вы хотите использовать другие типы mime , вы всегда должны принудительно загружать их, никогда не включать их в веб-страницы, если вы действительно не знаете, что делаете …

     X-Download-Options: noopen Content-Disposition: attachment; filename=untrustedfile.html 
  6. Внутри них возможно иметь действительные файлы изображений с кодом, например, в exif- данных. Таким образом, вы должны очистить exif от изображений , если его содержимое не важно для вас. Вы можете сделать это с помощью Imagick или GD , но для обоих из них требуется переупаковка файла. Вы можете найти exiftool в качестве альтернативы. Я думаю, что самый простой способ очистить exif , загружает изображения с помощью GD и сохраняет их как PNG с самым высоким качеством . Таким образом, изображения не потеряют качество, и тег exif будет очищен, потому что GD не сможет его обработать. Сделайте это с изображениями, загруженными как PNG тоже …
    Если вы хотите извлечь данные exif , никогда не используйте preg_replace() если pattern или replacement принадлежит пользователю, потому что это приведет к инъекции eval … При preg_replace_callback() используйте preg_replace_callback() вместо eval regex flag . (Общая ошибка в кодах копирования папок.) Данные Exif могут быть проблемой, если ваш сайт имеет уязвимость для инъекций , например, если вы используете include($userInput) где-то.

  7. Никогда не используйте include() , require() загруженными файлами , readfile() их как static или используйте file_get_contents() или readfile() или любую другую функцию чтения файлов, если вы хотите контролировать доступ.
    Он редко доступен, но я думаю, что лучший подход к использованию заголовков X-Sendfile: {filename} с модулем apache sendfile . По заголовкам никогда не используйте ввод пользователя без проверки или дезинфекции, поскольку это приведет к вводу заголовка HTTP .
    Если вам не нужен контроль доступа (означает: только авторизованные пользователи могут видеть загруженные файлы), а затем обслуживать файлы с вашего веб-сервера. Это намного быстрее …

  8. Используйте антивирус для проверки загруженных файлов, если он у вас есть.

  9. Всегда используйте комбинированную защиту , а не только один подход. Будет сложнее нарушить вашу защиту …

Используйте и настройте Hardened-PHP, создайте простой скрипт, используя файл move_uploaded_file и суперкоммулятор $ _FILES . Самый простой сценарий, самый безопасный он будет (по крайней мере, так же безопасен, как и запущенная версия PHP)