Как стать автором
Обновить

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

Самое смешное, что «знакомые расширения» апач тоже «откусывает».
phpfaq.ru/apache/blah.php.jpg — дефолтные настройки.

Поэтому рекомендуется заключать подключение PHP в контейнер
Упс, тег съелся.
В контейнер FilesMatch

<FilesMatch \.php$>
AddType application/x-httpd-php .php
</FilesMatch>

Это отобьёт Апачу охоту умничать при определении MIME-типа:
phpfaq.ru/good/blah.php.jpg
phpfaq.ru/good/blah.php
Мне понравилась формулировка «отобьёт Апачу охоту умничать...»
Лучше всё же так
<FilesMatch "\.php$">
	SetHandler application/x-httpd-php
</FilesMatch>

Чтобы уж не бояться случайного пропуска FilesMatch, без которого AddType превращается в способ выполнения каких угодно файлов как PHP скриптов, содержащих ".php" в любом месте имени.
Я проверяю MIME вот так.

/**
* Метод определяет MIME-тип файла.
* @todo move to class_mime
* link www.iana.org/assignments/media-types/index.html
* return
* bool false в случае, если файл не существует.
* str MIME-тип файла.
*/
static public function get_mime($filename){
if( is_file($filename) == true ){
$finfo = finfo_open(FILEINFO_MIME_TYPE, '/usr/share/file/magic.mgc');
$mimetype = finfo_file($finfo, $filename);
if( $mimetype === false )
return false;
finfo_close($finfo);
return $mimetype;
}else{
return false;
}
}
Есть тег source на Хабре…
И как это поможет против картинки с приписанным PHP-кодом в конце файла или в метаданных?
if( is_file($filename) == true ) — мощно сказано
Вот так же надо!
if ( (is_file($filename) == true) == true)
Вообще-то is_file — это проверка аналогичная file_exists.

$filename — это абсолютный путь к файлу. Мало ли как называется переменная $filename или $path_to_file.

is_file — Возвращает TRUE, если файл существует и является обычным файлом, иначе возвращает FALSE.

спасибо кэп, только зачем bool сравнивать с bool?)
еще маленькая поправка — функция is_file проверяет существование файла и возможность выполнения с ним операций чтения/записи. Так же результат кешируется. Функция file_exists — просто проверяет наличие файла и, по-моему, директории.

А что значит «и является обычным файлом»? какие файлы еще бывают?
какие файлы еще бывают?

директории, блочные и символьные устройства, возможно еще какие-то варианты есть.
«is_file — Возвращает TRUE, если файл существует и является обычным файлом, иначе возвращает FALSE.» — это из официальной русской документации с php.net.

Есть ещё is_link и is_dir — ссылка и директория, это ведь тоже файлы, исходя из этого контекста используется словосочетание «обычным файлом».

SILENTNUKE — причём тут моя стилистика написания кода, хочу и указываю явно сравнение с bool. Или ты типичный ХАБРАТРОЛЛЬ? Здесь идёт обсуждение конкретной темы, а мой рецепт дополнение к этой конкретной теме, к определению MIME. Или у тебя туалета дома нет и ты тут решил сходить.
Не стоит так ругаться. Стилистика тут не при чём. Оператор if работает с булевыми выражениями, а is_file возвращает именно его, и поэтому дополнительное сравнение является избыточным.

Если тебе указали на ошибку, то лучше попросить объяснить, чем отругиваться.
Это не ошибка! Ну насмешил «Если тебе указали на ошибку». У меня стилистика явно указывать сравнение с boolean!
Когда ты столкнёшься с большим проектом и с «неуловимой» проблемой в коде, что я опишу ниже, ты начнёшь делать также, как и я, то есть явно сравнивать.
И если вы, никогда не работали с проектом, в котором 1 000 000 строк исполняемого PHP кода, то вам не понять мой подход явного указания сравнения.

В моём рецепте функция finfo_file($finfo, $filename) может вернуть mixed значение: строку или boolean. И в этом случае понятно, что всё что не false будет восприниматься как true,
поэтому можно записать if( !$mimetype ).

Но бывают такие функции, которые возвращают значения: true (строка, число, массив), false или null.

True, строка, число, массив — может означать, что функция отработала успешно и вернула какой-то результат.

False — будет означать то, что произошла ошибка.

Null — будет означать, что функция отработала верно, но вернула пустоту.

И с таким раскладом True/False/Null в PHP есть ряд функций, да и в собственных тоже такое бывает. И чтобы мне не заморачиваться, я выбрал именно правильный для меня подход, писать всегда явно определение true, false и null.

if( !my_function() ){

// Код, который нужно выполнить только в случае ошибки.
// Но, если функция отработала корректно и
// вернула пустой результат Null, то мы также окажемся здесь. А мне этого не нужно!

}

// Поэтому местным троллям в случае описываемой ситуации, также придётся писать явное сравнение.

if( !my_function() ){

// Код, который нужно выполнить только в случае ошибки.

}else if( my_function() == null ){

// Код, который нужно выполнить только при пустом значении.

}

// Но так как, у меня своя стилистика, богатый опыт и профессиональный подход, я пишу всегда явно.
// Теперь вы понимаете тролли? И тут тролли закричали в один голос: «Прости нас идиотов...»

if( my_function() == false ){

// Код, который нужно выполнить только в случае ошибки.

}else if( my_function() == null ){

// Код, который нужно выполнить только при пустом значении.

}

Я очень рад за местных многоуважаемых троллей и за то, что любимый PHP позволяет опускать boolean сравнение в if.

Но мне нравится, так как я пишу, потому что застрахован от таких нелепых ошибок! И не нужно отнимать моё время на пустой трёп, чтобы доказывать троллям, что они тролли.

Вместо того, чтобы обсирать мой код, лучше бы дополнили статью полезными материалами, давая какие-то решения.
Я очень рад за местных многоуважаемых троллей и за то, что любимый PHP позволяет опускать boolean сравнение в if.


Дело не в вашем любимом PHP. Это программирование и концепция типов данных (см. Никлаус Вирт «Алгоритмы и структуры данных»)

Но мне нравится, так как я пишу, потому что застрахован от таких нелепых ошибок! И не нужно отнимать моё время на пустой трёп, чтобы доказывать троллям, что они тролли.
Не застрахованы. Сравните смысл равенства == и эквиваленции === в вашем любимом языке. И заодно про приведение типов.

// Но так как, у меня своя стилистика, богатый опыт и профессиональный подход, я пишу всегда явно.
// Теперь вы понимаете тролли? И тут тролли закричали в один голос: «Прости нас идиотов...»

Мне вас жаль. И вашу учительницу информатики.

Не шучу. И не троллю.
Поправлюсь, пока тролли спят.

if( my_function() === false ){

// Код, который нужно выполнить только в случае ошибки.

}else if( my_function() === null ){

// Код, который нужно выполнить только при пустом значении.

}

Буду краток и откровенен.

Мне нелегко об этом писать, но правда заключается в том, что таких гениальных и талантливых людей, как Я — единицы. Нас всегда ущемляют в правах, пытаются высмеять и вытеснить, серая масса люмпенов программистов, да и просто бездарные люди. Вот и на Хабре, тот самый случай, я могу постить комментарии 1 раз в час. Ах, какое не справедливое сообщество. Ладно, пошёл себе арбуз рубану.
Сообщите, когда будет готова принципиально новая ОС.
Так она давно готова
И на каждом сравнении будет вызываться my_function()?
Страшно представить, что у вас там за проекты на 1кк строк… Талантливый вы наш и гениальный…
британские ученые отдыхают. неделя юного кодоиспытателя на хабре.
И как раз на том же Stackoverflow дали нормальный ответ — прогонять все фотографии через GD или Imagemagick.
Вас, возможно, шокирует, что PHP-код можно вставить и в данные самого изображения, и тогда этот код выживет пересохранение в тот же формат?
Пересохранение.
Обработка с помощью GD убьёт любые посторонние данные по умолчанию, а Imagemagick-у надо при конвертации об этом специально сказать. Впрочем, я не возьмусь назвать конкретные ключи, которые в этом случае надо применить — кроме EXIF-а наверняка есть ещё лазейки.
Я всегда при загрузке картинок вписываю картинку в рамку, то есть я меняю размер картинки через GD и сохраняю в jpg всякие фотки, аватарки и т.д.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
php — injection
PS. Или в паре с некоторыми другими типами узвимостей.
НЛО прилетело и опубликовало эту надпись здесь
Конкретно этой ошибки у Вас может не быть, но может быть неправильная настройка сервисов администратором, может быть ошибка в стороннем ПО.
Количество различных вариаций уязвимостей ограничивается лишь фантазией злоумышленника, и то что он смог загрузить вредоносный код, пусть пока и без возможности запустить его, явно не достижение.
PS. Лучше сбить свой самолет, чем пропустить вражеский.
ИМХО бороться таки нужно с сыростью, а не плесенью. А сырость в том, что Apache неадекватно реагирует на определенные имена файлов.

Вообще, apache — достаточно слабый способ отдавать статику, lighttpd или nginx делают это гораздо лучше. Таким образом, если отдавать статику через nginx (без настроенных обработчиков CGI), то заливка любого файла оставит систему в целости и сохранности, будь у вас там многоэтажные проверки или нет.

Хотя все же даже с nginx-ом следует проверить файл, но уже просто для удобства пользователя. Чтобы другие ваши посетители видели целую и валидную картинку. При этом можно держать градус паранойи на низком уровне, т.к. система в любом случае в безопасна.
По большой счёту решение сводится к:
  • не использовать голый AddType для задания обработчика скриптов;
  • никогда не доверять user input;
  • явно отключать выполнение скриптов для директорий со статикой.


Вообще, apache — достаточно слабый способ отдавать статику, lighttpd или nginx делают это гораздо лучше

Непонятно только, причём здесь описанные в посте уязвимости.
При том, что 99% статьи является workaround-ом против фундаментального недостатка: в папке со статикой тем или иным способом может быть выполнен PHP скрипт. Далее, основываясь на всего лишь этом одном недостатке перечислел 101 способ его проэксплуатировать и описано 202 проверки, противоборствующие этому 101 способу.

Устраните всего лишь один этот фундаментальный недостаток при помощи того же nginx — и вся статья теряет смысл.
Храню файлы с именем в виде хэша а всю информацию (имя файла, mime etc) отдельно, очень удобно.
Что такое самоуверенный проект? Почему это словосочетание встречается в статье несколько раз? Где названия и адреса репозиториев этих самоуверенных проектов?
НЛО прилетело и опубликовало эту надпись здесь
если злоумышленник получил доступ на уровне системы, он и так может все сделать

Например, случаются уязвимости, дающие возможность удалять (но не создавать или изменять) произвольные файлы. (Предположим, эта уязвимость в каком-нибудь совсем другом углу сервера, не относящемся к уязвимому веб-сайту.)
Без загрузки image.php.jpg это лишь бессмысленный и беспощадный DoS, а с ним — выполнение кода.
НЛО прилетело и опубликовало эту надпись здесь
Видимо, вы плохо осведомлены, как некоторые личности настраивают свои сервера…
А не проще ли вообще сделать доступ к картинкам через отдельный скрипт и закрыть прямой доступ к папке с ними? Тогда никто и не сможет выполнить их.
НЛО прилетело и опубликовало эту надпись здесь
Ну да. Не может:
Но не надо забывать, что по умолчанию интерпретатор PHP вызывается ещё и для расширений .phtml и .php3, а некоторые хостеры включают его и для других расширений — порой даже для .html, .js, .jpg и так далее, чтобы вставлять в статические ресурсы какой-нибудь SEO-код, или отслеживать статистику хитов.

Черным по белому сказано, что при большей везучести можно выполнить все. Инъекция так делается: в изображение вставляется код и его отследить становится сложнее.
А нагрузка на сервер мизерная получается по-сравнению с пользой от такого метода.
Я бы не стал так утверждать, про нагрузку.
Тем более, что в статье есть более простое решение — запретить исполнение скриптов в этой папке.
НЛО прилетело и опубликовало эту надпись здесь
При проблемах с нагрузкой вероятнее всего вы захотите загружать картинки на отдельный сервер, где стоит nginx, отдающий только статику, без возможности выполнения скриптов. Если отдельного сервера нет-то нет и проблем с нагрузкой ;).
НЛО прилетело и опубликовало эту надпись здесь
Этот отдельный скрипт тоже частенько бывает решетом без basename().

pic.php?img=../../../etc/passwd
Ну само собой, прямые руки и мысли головой никто не отменял :)
К тому же можно так:
file.php?name=image&ext=jpg
и удалять из имени файла парные точки
Вот проблема ( ваша и OnYourLips ) как раз в том, что вы отказываетесь действовать по принципу белого списка (запрещено всё, что не разрешено) и предпочитаете действовать по принципу списка чёрного — разрешено всё, что не запрешено.
Но чёрный список заведомо дырявее белого. Всё предусмотреть невозможно. И, скажем, добраться до какого-нибудь файла с паролями можно будет и безо всяких точек.
НЛО прилетело и опубликовало эту надпись здесь
Безопасность во многом зависит от администраторов, а не разработчиков. В вашем коде нет места php-include, но настройки сервера позволяют запустить файл в upload, включая чтение файлов движка или его конфигов. Ваш код будет идеален, но злоумышленник получит возможность, например, доступа к БД с правами вашего кода. Кстати, отчасти поэтому я советую заказчикам взять shared хостинг или нанимать админа, а не берусь настроить им vds. Разве что сильно настаивают когда занимаюсь администрированием.
Или есть риск потерять заказ :(
НЛО прилетело и опубликовало эту надпись здесь
При сохранении всегда использую ID изображения в базе и при открытии по ID делаю intval.
Ну, как минимум следует учитывать возможность инклюда с локального диска.
Понятно, что инклюды надо защищать отдельно, но программисты обычно не слишком заботятся о безопасности внутренних инклюдов. А проверку на open_basedir картинка пройдёт спокойно.

Опять же, sun.php.jpg оказывается куда более разрушительным. Так что не все рекомендации в статье одинаково бесполезны.
НЛО прилетело и опубликовало эту надпись здесь
Я же пример привел, работающий. В самом первом комментарии к топику.

Собственно, практически любой фреймфорк запускает PHP файлы в зависимости от пользовательского ввода. Очень часто части запрошенного урла совпадают с названиями файлов/методов имеющихся классов.
А фильтрация всего этого дела остаётся на совести программиста.
НЛО прилетело и опубликовало эту надпись здесь
Многие из описанных вами методов уже давно обходятся при наличии интеллекта и желания.
Поведайте, будем рады!
это альтернативные способы, есть еще и приватные, но о них мало кто говорит. Я бы хотел дополнить, что приведенные вами примеры эффективны только при использовании их в качестве целого элемента системы, т.е. если использовать их не в комплексе, то толку от них мало.
Хабр съел ссылку _http://www.youtube.com/watch?v=2WCGyQ4ldC0 А по поводу более скрытого я имел в виду например ограничение на длину имени файла и альтернативу null байта. Но все зависит от версии PHP
Добавлю:
в пакетах libapache2-mod-php5 и mime-support для Debian (возможно, и для Ubuntu) по умолчанию используется потенциально небезопасная конфигурация.

В /etc/mime.types для application/x-httpd-php прописаны расширения .php .phtml .pht (!!!)
При этом в /etc/apache2/mods-available/php5.conf есть строчка
<FilesMatch "\.ph(p3?|tml)$">

беда которой в том, что она создает чувство ложной защищенности, т.к. с такими mime.types все работает и без нее.
И, вероятно, не совсем так, как вы ожидаете — как насчет файла с замечательным именем «hello.pht.en»?

Эта «черная магия» отключается дописыванием строки
RemoveType .php .pht .phtml .php3 .php4 .php5

все в тот же php5.conf.

Кстати в фабричных настройках Debian эта уязвимость появилась почти 10 лет назад.
archive.debian.org/debian/pool/main/m/mime-support/
mime-support_3.9-1.3.tar.gz 30-Apr-2003
archive.debian.org/debian/pool/main/a/apache/
apache_1.3.26-0woody6.diff.gz 17-Nov-2004

«Don't Add Security, Remove Insecurity»
>> В последней версии PHP, судя по моим экспериментам, $_FILES[«file»][«name»] и так возвращает только basename от переданного в HTTP-запросе значения filename; но осторожность тут лишней не будет.
Про лишнюю осторожность бред конечно, а вот до какой версии оно возвращало не basename?
можно ещё анализировать содержимое файла, например так:

$content = file_get_contents ( 'загруженный файл' );

if ( stristr( $content, '<?' ) OR stristr ( $content, '<%' ))
{
     die();
}
Отлично подходит для ситуаций, когда пару десятков пользователей в параллели будут загружать большие картинки. )
пример накидал самый простейший, можно оптимизировать
Хорошо, предположим оптимизировали. А как быть с бинарными файлами, которые вполне могут содержать эти сочетания байт? Вероятность появления сочетания двух определённых байтов — 1/2^8^2, то есть в среднем одно такое сочетание на файл размером 64Ки.
Два правила начинающему комментатору:
1. Если эта идея прямо сейчас пришла вам в голову, то надо сначала проверить — насколько она применима в реальной жизни.
2. Если вы к этой идее не имеете вообще никакого отношения, а просто повторяете за кем-то — тем более надо сначала проверить — насколько она применима в реальной жизни. Чтобы не быть одним из миллионов разносчиков мусора.

В качестве домашнего задания попробуйте поискать эти сочетания в любой мало-мальски объемной коллекции заведомо безопасных картинок.
НЛО прилетело и опубликовало эту надпись здесь
Чужие или не чужие, обязаны или не обязаны — зависит лишь от TOS.
Не понял, как именно поступать?
Он же никак эти данные не портит, а просто предлагает не принимать.
Сайт и не обязан принимать всё подряд.
Смысла я в такой проверке не вижу, но и никаких проблем с пользовательскими данными — тоже
НЛО прилетело и опубликовало эту надпись здесь
У вас все в кучу перемешалось.
Я не предлагаю делать эту тупую проверку на "&lt?".
Эта проверка сама по себе дурацкая и не имеет смысла.

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

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

А чтобы заказчики не звонили, надо просто выдавать внятные сообщения об ошибках и собирать их в отчет, выдаваемый по запросу.
А чтобы на кофейной гуще не гадать — нужно обязательно логировать весь процесс.
Кому я что обязан на своём сайте?
Как раз проверял написаное в статье на своем хомяке — открыл jpg-шку с подсветкой синтаксиса php (Notepad++) и штуки три <? нашлось.
была уже тема на хабре.

1) отключить выполнение php в папке с хранением картинок.
2) рандомные имена и пути + расширение присваивается сервером.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Какое дело SEOшникам для имён статических файлов?
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
рандомные пути… наверное не точно выразился… не скрипт запрета нахождения файла физически.ДОстатчно будет просто рандомного имени + расширение от сервера + запрет выполнения php в папке и достаточно.
>Придется отдавать скриптом, чтобы подставлять правильные имена.
Необязательно, в большинстве CMS в БД хранится этот рандомный адрес и указывается сразу в ссылке на файл.
Очень часто при загрузке картинок нужен их ресайз. Так что если он не удался по понятным причинам, то трём файл.
Тут уже упоминалось, что ресайз ресайзу рознь.
Многие современные методы обработки картинок бережно сохраняют имеющиеся в файле метаданные.
НЛО прилетело и опубликовало эту надпись здесь
AFAIK, 'это mod_mime.
mod_negotiation тоже поминали, в виде file.php.en
Вообще не вижу проблемы — вынести все в отдельную папку. В идеале — раздавать с отдельного домена (пусть даже поддомена) с помоью nginx.
Если хостинг совсем плохой и есть только апач то отрегистрировать все расширения, убрать возможности запуска любых скриптов и SSI для файлов в этой папке.
if (preg_match('#\<\?.*\?\>#si',file_get_contents($_FILES['bablabla']))) die('oops');
А вот уж потом move_uploaded_file. У вас же там не гигабайтные файлы загружаются?
Ну а если они не гигабайтные, но сразу довольно приличное кол-во?
Ну я думаю прег-мач не сильно нагрузит
Ошибка — закрывающий тег не обязателен. Его убрать, открывающий оставить, а Ваш скрипт его пропустит. Всё, взломано.
Ну, идею я донес
Идею уже доносили до вас.
Ну в таком случае она еще больше укрепится в сознаии обывателей
Надеюсь, наоборот.
Ну ок, дело ваше
НЛО прилетело и опубликовало эту надпись здесь
Куда грустнее, когда есть CMS (или блог, или еще какой _готовый_ софт), к нему понаустанавливали модулей — и это все надо защитить. Аудит кода устраивать не самый лучший вариант. Аудит настроек сервера — хорошо, если сервер наш, но ведь бывает и shared-хостинг, где сегодня вот так все настроено, а завтра что-то тихо ка-а-а-а-ак поменяется…

Я к тому, что порой проще (и надежнее) вспомнить про тот же cloudflare.com, чем грызть себе ногти, ругаясь на чужой код на своем сервере.
Можно убрать «недопустимые» символы в имени файла. То есть сразу убираем точки (кроме одной) и слэши из имени, а потом уже проверяем расширение. Обязательное пересохрание это изврат какой то. А если ворд документы пойдут или пдф, тоже пересохранять? :)
Достаточно часто встречаются ситуации когда люди пользуются какой либо функцией в фреймворке для описанных вами и совсем уж очевидных проверок, а сохраняют файл собственными силами и тогда оказывается, что при проверке делается trim (к примеру) а при сохранении вы его не делаете, что позволяет загрузить изображение с именем «file.jpg » и провернуть XSS для пользователей IE.
И совсем забыли об одной еще достаточно хитрой особенности nginx — нельзя допускать загрузки картинок без имени, только с расширением (например ".jpg"), т.к.:

anri@AKrasichkov:~$ curl -I http://localhost/test.gif | grep Content-Type
Content-Type: image/gif


anri@AKrasichkov:~$ curl -I http://localhost/.gif | grep Content-Type
Content-Type: application/octet-stream


Имхо, считаю статью из серии К.О.
Куда более интересней вопрос — правильная загрузка/отдача любых произвольных файлов, т.к. помимо изображений все чаще есть необходимость в загрузке тех же аудио/видео/офисный и иных файлов.
К слову сказать, файлов «без имени» не существует. В данном случае вы продемонстрировали файл с
именем ".jpg".

А «хитрая» особенность nginx заключается в том, что в отличии от апача заголовок «Content-Type» устанавливается по расширению и абсолютно ни на что не влияет с точки зрения обработки запроса. И при отсутствии расширения берется из директивы «default_type» с безобидным по-умолчанию значением.
Да, вы правы фактически имя у файла ".jpg" просто как иначе «обозвать» подобные файлы я увы не придумал, посему счел уместным употребить именно такое обозначение. Возможно, говорить «файлы без названия» было бы более корректным.

application/octet-stream безобидное? С чего бы вдруг? А как же mime-сниффинг в IE, включенный у абсолютного большинства его пользователей? Как раз по этой причине у меня обычно «default_type» и выставлен в force-download.
«default_type» не может быть выставлен в «force-download» — это делается другим заголовком.

Что касается mime-сниффинга в IE то, если мне не изменяет память, он работает только если пользователь открывает файл прямой ссылкой, а не браузер загружает по тегу на странице, и когда он работает, то какой бы «Content-Type» вы не выставили — это не поможет.

В общем же случае, если вы допускаете загрузку скриптов на ваш сервер — у вас уже проблемы, и рано или поздно кто-нибудь найдет способ это поэксплуатировать.
Хм, перепроверил — а вы правы, черт побери! Видимо я последние тесты проводил или со странной сборкой IE или еще что, в любой случае склоняю шляпу, век живи — век учисью.

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

А с этим никто и не спорит, вопрос в другом — как максимально обезопасить свой аплоад разработчикам которые не знают на какой конкретной конфигурации будет работать их код (разработчики CMS/CMF, модулей и т.д.). Вот и приходится искать все возможные «странности» и подстраиваться под них, как в моем примере с nginx + файл только с расширением. Люди ведь извращенцы, некоторые работают и на связке IIS+PHP. С позиции разработки проекта все прозрачно — используем CDN, другой домен для статики и т.д.
В ISPManager не так уж просто отключить PHP для image.php.jpg

Но решение есть. Может пригодится:

1. Создаем скрипт для вставки нужных инструкций в /etc/apache2/apache2.conf:

disable-apache-php-vuln.pl
#!/usr/bin/perl
use strict;

my $fn = "/etc/apache2/apache2.conf";

open(FILE, '<', $fn);
my $data = join("", <FILE>);
close(FILE);

$data =~ s|DocumentRoot\s+([^\s]+)|DocumentRoot \1
    <Directory \1>
        RemoveHandler .php .pht .phtml .php3 .php4 .php5
        RemoveType    .php .pht .phtml .php3 .php4 .php5
        <FilesMatch "\\.ph(p3?\|tml)\$">
            SetHandler application/x-httpd-php
        </FilesMatch>
    </Directory>|g;

open(FILE, '>', $fn);
print FILE $data;
close(FILE);


2. Делаем копию /etc/apache2/apache2.conf и запускаем
perl disable-apache-php-vuln.pl

3. Перезапускаем апач.

4. Теперь добавим нужные инструкции для новых сайтов создав /usr/local/ispmgr/etc/virtualhost.templ с таким содержимым:
    DocumentRoot __DocumentRoot__
    <Directory __DocumentRoot__>
        RemoveHandler .php .pht .phtml .php3 .php4 .php5
        RemoveType    .php .pht .phtml .php3 .php4 .php5
        <FilesMatch "\.ph(p3?|tml)$">
            SetHandler application/x-httpd-php
        </FilesMatch>
    </Directory>

5. Перезапускаем ispmgr:
killall ispmgr

Почему так сложно?
Просто ispmanager не умеет по другому включать php для сайта. Только через
    AddType application/x-httpd-php .php .php3 .php4 .php5 .phtml

И я не знаю как изменить это.
Прочитал статью, прочитал комменты, почесал репу. Не совсем понятно, что делает злоумышленник дальше, после того как загрузил файл с php кодом? Ведь этот файл еще надо как то выполнить.

У меня допустим аплоадятся картинки и складываются в не-www директорию, и единственное, что с ними делается это file_get_contents и echo. Есть ли в этом случае возможность выполнять код загруженной картинки?

И самое главное, статья с учетом комментариев так и не раскрыла тему защиты.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории