Каков наиболее безопасный способ для загрузки файла?
В компании, с которой я работаю, недавно были задействованы многие эксплоиты для встраивания заголовков и загрузки файлов на узлах, которые мы размещаем, и хотя мы исправили проблему в отношении атак на вставку заголовков, нам еще предстоит получить подсистемы подгрузки.
Я пытаюсь настроить серию сценариев загрузки "plug-and-play-type" для использования внутри компании, которые дизайнер может скопировать в свою структуру сайта, изменить несколько переменных и иметь готовые к использованию загрузить форму на свой сайт. Мы стремимся максимально ограничить нашу экспозицию (мы уже закрыли команды fopen и shell).
Я искал сайт в течение последнего часа и нашел много разных ответов, касающихся конкретных методов, которые полагаются на внешние источники. Что вы считаете лучшим решением script, которое достаточно конкретно для использования в качестве надежного метода защиты? Кроме того, я бы хотел, чтобы язык был ограничен PHP или псевдокодом, если это возможно.
Изменить: Я нашел свой ответ (размещен ниже) и, хотя он использует команду оболочки exec(), если вы блокируете script файлы от загрузки (что решение очень хорошо), вы не столкнетесь с какими-либо проблемами.
Ответы
Ответ 1
Лучшим решением, IMHO, является размещение каталога, содержащего загруженные файлы вне "веб-среды", и использование script, чтобы сделать их загружаемыми. Таким образом, даже если кто-то загружает script, он не может быть выполнен, вызывая его из браузера, и вам не нужно проверять тип загружаемого файла.
Ответ 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
-
Вы должны использовать $_FILES
и move_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);
Всегда генерировать случайный идентификатор вместо использования исходного имени файла.
-
Создайте новый субдомен, например 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()
для вновь загруженных файлов и установите его в каталог.
-
Вам следует проверить тип 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
-
В файлах exif возможно иметь действительные файлы изображений с кодом, например. Таким образом, вы должны очистить exif от изображений, если его содержимое не важно для вас. Вы можете сделать это с помощью Imagick
или GD
, но для обоих из них требуется переупаковка файла. Вы можете найти exiftool
в качестве альтернативы.
Я думаю, что самый простой способ очистить exif - загрузка изображений с помощью GD и сохранить их как PNG с самым высоким качеством. Таким образом, изображения не потеряют качество, и тег exif будет очищен, потому что GD не сможет его обработать. Сделайте это с изображениями, загруженными как PNG тоже...
Если вы хотите извлечь данные exif, никогда не используйте preg_replace()
, если pattern
или replacement
принадлежит пользователю, потому что это приведет к инъекции eval... Используйте preg_replace_callback()
вместо eval regex flag
, если необходимо. (Общая ошибка в кодах копирования.)
Данные Exif могут быть проблемой, если ваш сайт имеет уязвимость в отношении инъекций, например, если вы используете include($userInput)
где-то.
-
Никогда не используйте include()
, require()
загруженные файлы, ставьте их или используйте file_get_contents()
или readfile()
или любую другую функцию чтения файлов, если вы хотят контролировать доступ.
Он редко доступен, но я думаю, что лучший подход к использованию заголовков X-Sendfile: {filename}
с модулем sendfile apache. По заголовкам никогда не используйте ввод пользователя без проверки или дезинфекции, потому что это приведет к вводу заголовка HTTP.
Если вам не нужен контроль доступа (означает: только авторизованные пользователи могут видеть загруженные файлы), а затем обслуживать файлы с вашего веб-сервера. Это намного быстрее...
-
Используйте антивирус, чтобы проверить загруженные файлы, если он у вас есть.
-
Всегда используйте комбинированную защиту, а не только один подход. Это будет труднее нарушить вашу защиту...
Ответ 3
Использовать и настраивать Hardened-PHP создать простой script с помощью move_uploaded_file и $_ FILES суперглобальный. Самый простой script, самый безопасный он будет (по крайней мере, так же безопасен, как и запущенная версия PHP)