Прекратить загрузку вредоносных файлов PHP через формы - PullRequest
28 голосов
/ 02 марта 2009

У меня есть форма загрузки, созданная на php на моем веб-сайте, где люди могут загружать zip-файлы. Затем zip-файл извлекается и все местоположения файлов добавляются в базу данных. Форма загрузки предназначена для людей, которые могут загружать только изображения, очевидно, поскольку файлы находятся в папке zip, я не могу проверить, какие файлы загружаются, пока файл не будет извлечен. Мне нужен фрагмент кода, который удалит все файлы, которые не являются форматами изображений (.png, .jpeg и т. Д.). Я действительно беспокоюсь о том, что люди могут загружать вредоносные файлы php, большой риск для безопасности! Мне также нужно знать, что люди, меняющие расширения php-файлов, пытаются обойти эту функцию безопасности.

Это оригинальный скрипт, который я использовал http://net.tutsplus.com/videos/screencasts/how-to-open-zip-files-with-php/

Это код, который на самом деле извлекает ZIP-файл:

function openZip($file_to_open) {
    global $target;

    $zip = new ZipArchive();
    $x = $zip->open($file_to_open);
    if($x === true) {
        $zip->extractTo($target);
        $zip->close();

        unlink($file_to_open);
    } else {
        die("There was a problem. Please try again!");
    }
}

Спасибо, Бен.

Ответы [ 10 ]

63 голосов
/ 02 марта 2009

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

Верхушка айсберга!

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

Как правило, изменение расширений не позволит PHP интерпретировать эти файлы как сценарии. Но это не единственная проблема. Есть больше вещей, чем "... php", которые могут повредить серверную часть; «.Htaccess» и файлы с установленным битом X - очевидные, но далеко не все, о чем вам нужно беспокоиться. Даже если игнорировать вещи на стороне сервера, существует огромная проблема на стороне клиента.

Например, если кто-то может загрузить файл «.html», он может включить в него тег , который перехватывает сеанс стороннего пользователя и удаляет все загруженные им файлы или меняет свой пароль или что-то в этом роде. Это классическая атака между сайтами (XSS).

Кроме того, благодаря поведению некоторых браузеров (в основном IE), «перехвата содержимого», файл, загруженный как «.gif», может фактически содержать вредоносный HTML, такой как этот. Если IE видит контрольные сигналы, такие как (но не ограничиваясь ими) ‘’, в начале файла, он может игнорировать обслуживаемый Type Content-Type ’и отображаться как HTML, что приводит к XSS.

Кроме того, можно создать файл, который и является допустимым изображением, которое будет принимать ваш анализатор изображений, и содержат встроенный HTML. Существуют различные возможные результаты в зависимости от точной версии браузера пользователя и точного формата файла изображения (в частности, JPEG имеют очень переменный набор возможных форматов заголовков). В IE8 есть смягчения , но сейчас это бесполезно, и вам нужно задаться вопросом, почему они не могут просто перестать заниматься перехватом контента, вы, идиоты MS , вместо того, чтобы обременять нас с нестандартными нестандартными расширениями заголовков HTTP, которые в первую очередь должны были иметь Just Worked.

Я снова нападаю. Я остановлюсь. Тактика безопасного обслуживания предоставленных пользователем изображений:

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

Даже если вы взяли что-то очень ограничительное, например «только буквы ASCII», вам все равно придется беспокоиться о слишком длинных, слишком коротких и зарезервированных именах: попробуйте сохранить файл с таким же безобидным именем, как «com.txt». На сервере Windows и наблюдайте за тем, как ваше приложение отключается. Думаешь, ты знаешь все странные слабости путей к именам каждой файловой системы, на которой может работать твое приложение? Уверенный?

Вместо этого сохраните сведения о файле (например, имя и тип носителя) в базе данных и используйте первичный ключ в качестве имени в вашем хранилище файлов (например, «74293.dat»). Затем вам потребуется способ обслуживания их с разными видимыми именами файлов, например сценарий загрузчика, выплевывающий файл, сценарий загрузчика, выполняющий внутреннее перенаправление веб-сервера, или перезапись URL-адреса.

2: Будьте очень, очень осторожны, используя ZipArchive. В экстракте * были обнаружены уязвимости того же типа, которые затронули большинство наивных ZIP-экстракторов на основе путей. Кроме того, вы открываете себя для атаки из ZIP бомб . Лучше всего избегать опасности неправильных имен файлов, просматривая каждую запись файла в архиве (например, используя zip_read / zip_entry _ *) и проверяя его детали, прежде чем вручную распаковывать свой поток в файл с известным именем и флаги режима, которые вы создали без помощи архива. Игнорируйте пути к папкам внутри ZIP.

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

4: Если вы можете обойтись без загрузки всех ваших изображений (т. Е. Используя «Content-Disposition: attachment» в скрипте загрузчика), вы, вероятно, в безопасности. Но это может быть слишком неудобно для пользователей. Это может работать в тандеме с (3), тем не менее, предоставляя встроенные обработанные изображения меньшего размера и имея исходные изображения более высокого качества, доступные только для загрузки.

5: Если вам нужно показывать неизмененные изображения встроенными, вы можете устранить риск межсайтовых сценариев, обслуживая их из другого домена. Например, используйте «images.example.com» для ненадежных изображений и «www.example.com» для основного сайта, который содержит всю логику. Убедитесь, что файлы cookie ограничены только правильным виртуальным хостом и что виртуальные хосты настроены таким образом, что они не могут отвечать ни на что, кроме своих собственных имен (см. Также: Атаки на повторное связывание DNS). Это то, что делают многие службы веб-почты.

Таким образом, пользовательский медиа-контент является проблемой.

В кратком изложении, AAAARRRRRRRGGGGHHH.

ETA re comment:

вверху вы упомянули про 'файлы с установленным битом X', что вы подразумеваете под этим?

Я не могу говорить за ZipArchive.extractTo(), так как я не проверял его, но многие экстракторы, когда их просят сбросить файлы из архива, воссоздают [некоторые из] флагов режима файла Unix, связанных с каждым файлом ( если архив был создан на Unix и поэтому фактически имеет флаги режима). Это может вызвать проблемы с разрешениями, если, например, отсутствует разрешение на чтение для владельца. Но это также может быть проблемой безопасности, если ваш сервер поддерживает CGI: бит X может позволить интерпретировать файл как скрипт и передавать его любому интерпретатору скриптов, указанному в хэш-банге в первой строке.

Я подумал, что .htaccess должен быть в главном корневом каталоге, разве это не так?

Зависит от настройки Apache, в частности, от директивы AllowOverride. Хостам общего назначения свойственно AllowOverride в любом каталоге.

что произойдет, если кто-то еще загрузит файл вроде ../var/www/wr_dir/evil.php?

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

Но я все равно не стал бы доверять extractTo() против враждебного ввода, есть слишком много странных маленьких файловых имен / каталогов, которые могут пойти не так, особенно если вы ожидаете когда-либо работать на серверах Windows. zip_read() дает вам гораздо больший контроль над процессом разархивирования, и, следовательно, злоумышленник гораздо меньше.

15 голосов
/ 02 марта 2009

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

Но, кроме того, вы должны знать, что некоторые форматы изображений допускают комментарии и другую метаинформацию. Это может быть использовано для вредоносного кода, такого как JavaScript, который некоторые браузеры будут запускать при определенных обстоятельствах (см. Рискованное прослушивание MIME в браузере Internet Explorer ).

9 голосов
/ 02 марта 2009

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

2 голосов
/ 02 марта 2009

Вы также можете рассмотреть возможность обнаружения mime-типов в следующей библиотеке:

http://ca.php.net/manual/en/ref.fileinfo.php

2 голосов
/ 02 марта 2009

Я не вижу риска переименования файлов php в вашей БД ... Пока вы не оцениваете их как файлы PHP (или вообще, если на то пошло), они не могут принести слишком много вреда, и поскольку расширение .php отсутствует, механизм php их не трогает.

Полагаю, вы также можете искать в файлах <?php ...

Также : предположите худшее из файлов, загруженных на ваш компьютер. Переименуйте папку, в которую вы сохраняете их, «вирусы» и относитесь к ней соответственно. Не делайте это публичным, не давайте никаких прав на запуск файла (особенно пользователю php) и т. Д.

1 голос
/ 04 марта 2009

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

1 голос
/ 02 марта 2009

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

Если вы действительно хотите удалить файлы, для php доступна библиотека zip . Вы можете использовать его для проверки имен и расширений всех файлов внутри загруженного zip-архива, и, если он содержит php-файл, выдайте пользователю сообщение об ошибке.

1 голос
/ 02 марта 2009

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

offtopic: не лучше ли позволить пользователю выбрать пару изображений вместо загрузки zip-файла. Лучше для людей, которые не знают, что такое почтовый индекс (да, они существуют)

0 голосов
/ 12 июля 2014

Используйте функцию getimagesize. Полная процедура: - 1.) Извлеките расширение изображения / загруженного файла, а затем сравните расширение с разрешенным расширением. 2.) Теперь создайте случайную строку для переименования загруженного файла. Лучшая идея - md5(session_id().microtime()). Его нельзя дублировать, и если ваш сервер работает очень быстро и может обрабатывать менее микросекунды, чем использовать инкрементную переменную и добавить их со строкой. Теперь переместите этот файл.

Совет Отключите обработку PHP-файлов в каталоге загрузки, это всегда предотвратит любую атаку на стороне сервера, и, если возможно, добавьте свой htaccess в корневой каталог или в файл конфигурации httpd и отключите файлы htaccess, теперь это решит ваши максимальные проблемы

0 голосов
/ 01 ноября 2013

Остерегайтесь этого Передача вредоносного PHP через getimagesize ()

Внедрение PHP через функции изображения, которые пытаются гарантировать, что изображения безопасны при использовании функции getimagesize ()

подробнее здесь http://ha.ckers.org/blog/20070604/passing-malicious-php-through-getimagesize/

Лучше для вашего логотипа пользователя использовать gravatar, как здесь используется Stackoverflow;)

...