Сделай Сам Свою Работу на 5

Использование глобальных переменных (Register_Globals)





 

Наверное, наиболее спорным моментом в разработке PHP стала замена значения по умолчанию для опции register_globals с ON на OFF в версии 4.2.0. Большинство пользователей доверилось разработчикам, даже не зная, что это за опция и как она влияет на работу PHP. Следует понимать, что сама по себе эта опция никак не влияет на безопасность, ургозу представляет некорректное использование предоставляемых ею возможностей.

В случае, если значение параметра register_globals ON, перед выполнением вашего кода будут инициализированы различные переменные, например, переменные, переданные при отправке формы. Также, учитывая тот факт, что PHP не требует инициализации переменных, написать потенциально опасный код очень легко. Это было очень спорным решением, но общество разработчиков PHP решило изменить значение по умолчанию этой директивы на OFF. В противном случае при написании кода разработчики не могли бы с уверенностью сказать, откуда пришла та или иная переменная и насколько она достоверна. До такого нововведения переменные, определяемые разработчиком внутри скрипта, и передаваемые пользователем внешние данные могли перемешиваться. Приведем простой пример злоупотребления конфигурационной опцией register_globals:



 

Пример 8.2.6.1:

 

<?

// устанавливаем переменную $authorized = true только для пользователей, прошедших авторизацию

if (authenticated_user()) {

$authorized = true;

}

 

// Поскольку в случае неудачи при проверке авторизации переменная $authorized

// не установлена, она может быть установлена автоматически, благодаря register_globals,

// например, при GET запросе GET auth.php?authorized=1.

// Таким образом, пройти эту проверку можно без авторизации

if ($authorized) {

include "/highly/sensitive/data.php";

}

?>

 

В случае register_globals = on логика работы скрипта может быть нарушена. В случае, если установленное значение off, переменная $authorized не может быть установлена из внешних данных запроса, и скрипт будет работать корректно. Но все же инициализация переменных - один из признаков хорошего тона в программировании. Например, в приведенном выше участке кода мы могли поместить $authorized = false в качестве первой строки. Такой код работал бы как со значением on, так и off опции register_globals, и подразумевая, что по умолчанию пользователь не проходил авторизацию.



Приведем еще один пример, использующий сессии. В случае, если register_globals = on, мы можем использовать переменную $username в приведенном ниже примере, но тогда у нас не будет уверенности в достоверности ее значения (к примеру, она могла быть передана в GET-запросе).

 

Пример 8.2.6.2:

 

<?

// Мы не знаем, откуда получена переменная $username, но точно знаем, что

// переменная $_SESSION хранит в себе данные сессии

if (isset($_SESSION['username'])) {

 

echo "Hello <b>{$_SESSION['username']}</b>";

 

} else {

 

echo "Hello <b>Guest</b><br />";

echo "Would you like to login?";

 

}

?>

 

 

Также существует возможность реализации оперативного реагирования в случае попытки подмены переменных. Так как во время разработки приложения мы знаем ожидаемое значение переменной, а также знаем ее достоверное значение, мы можем их сопоставить. Это не защитит код от подмены переменных, но усложнит перебор возможных вариантов. Если вы хотите знать, как именно были получены внешние данные, используйте переменную $_REQUEST, которая состоит из данных GET и POST запросов, а также данных COOKIE. Также, информацию об этом можно найти в разделе внешние данные в PHP.

 

Пример 8.2.6.3 (обнаружение попытки подмены переменных):

 

<?

if (isset($_COOKIE['MAGIC_COOKIE'])) {

 

// MAGIC_COOKIE получена из достоверного источника.

// Для полной уверенности необходимо проверить ее значение.

 

} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {

 

mail("admin@example.com", "Обнаружена попытка взлома", $_SERVER['REMOTE_ADDR']);

echo "Обнаружено нарушение безопасности, администратор уведомлен.";



exit;

 

} else {

 

// MAGIC_COOKIE в данных запроса не присутствует

}

?>

 

Следует понимать, что установка register_globals в off не сделает ваш код безопасным. Каждую полученную от пользователя переменную следует проверять на соответствие ожидаемому значению. Всегда проверяйте ввод пользователя и инициализируйте все используемые переменные. Для проверки на наличие неинициализированных переменных можно включить в опцию error_reporting() отображение ошибок категории E_NOTICE.

 

 

Данные, введенные пользователем

 

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

 

Пример 8.2.7.1 (потенциально опасное использование переменных)

 

<?

// удалить файлы из домашней директории пользователя...

// а может, еще что нибудь?

unlink ($evil_var);

 

// записать в лог-файл выполняемое действие...

// может быть, даже /etc/passwd?

fwrite ($fp, $evil_var);

 

// выполнение тривиальных действий... или rm -rf *?

system ($evil_var);

exec ($evil_var);

 

?>

 

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

 

- Будет ли данный скрипт воздействовать исключительно на предполагаемые данные?

- Правильно ли будут обработаны некорректные или нестандартные данные?

- Возможно ли использование скрипта непредусмотренным способом?

- Возможно ли его использование в сочетании с другими скриптами в негативных целях?

- Будет ли каждая транзакция корректно логирована?

 

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

Вы также можете предусмотреть отключение таких конфигурационных опций, как register_globals, magic_quotes и некоторых других, которые могут приводить к сомнениям относительно происхождения или значения получаемых переменных. Использование при написании кода режима error_reporting(E_ALL) может помочь, предупреждая вас об использовании переменных до инициализации или проверки (что предотвратит работу с данными, отличныи от ожидаемых).

 

 

Url fopen wrapper

 

Для увеличения функциональности и упрощения кодирования, разработчики php сделали такую особенность в функциях fopen, file, include и прочих. Если имя файла начинается с "http://", сервер выполнит HTTP-запрос, скачает страницу, и запишет в переменную как из обычного файла. Аналогично работают префиксы "ftp://", "php://" (последний предназначен для чтения и записи в stdin, stdout и stderr). Нужно это было для того, чтобы разработчики сайтов не мучались с библиотеками http-запросов и не писали их вручную. Данная опция отключается в настройках php, параметр allow_url_fopen.

 

CR/LF в HTTP-запросах

 

Комбинация символов carriage return и line feed в HTTP-запросе разделяет заголовки. Эту комбинацию символов можно передать в GET-запросе в виде "%0D%0A".

 

 

Untrusted input

 

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

Неопытный программист запросто может написать открытие файла без проверки данных:

 

<?

echo implode("", file(substr($REQUEST_URI, 1)));

?>

 

От запроса отбрасывается первый символ – слэш – и открывается файл. Злоумышленник легко может вписать в качестве пути к файлу на сервере строку

 

http://example.com: http://n00b.programmer.com/http://example.com

 

Другой вариант – все адреса на сайте имеют вид

 

http://n00b.programmer.com/index.php?f=news

 

В таком случае злоумышленник будет пробовать открыть адрес типа http://n00b.programmer.com/index.php?f=http://example.com Очень важно не доверять входящим данным и фильтровать при помощи регулярных выражений входящие запросы.

Поскольку в приведённом примере адрес никак не проверяется, в запрос можно вставить строку с HTTP-запросом. Если злоумышленник откроет путь (пример 8.2.10.1)

 

index.php?f=http%3A%2F%2Fexample.com%2F+HTTP%2F1.0%0D%0A%0D%0A

Host:+example.com%0D%0AUser-agent:+Space+Bizon%2F9%2E11%2E2001+

%28Windows+67%29%0D%0Avar1%3Dfoo%26var2%3Dbar%0D%0A%0D%0A

 

то скрипт выполнит HTTP-запрос (пример 8.2.10.2):

 

GET example.com/ HTTP/1.0\r\n

Host: example.com\r\n

User-agent: Space Bizon/9.11.2001 (Windows 67)\r\n

var1=foo&var2=bar\r\n

\r\n

HTTP/1.0\r\n

Host: www.site1.st\r\n

User-Agent: PHP/4.1.2\r\n

\r\n

 

Последние три строки скрипт добавляет автоматически, но два \r\n перед ними означают конец запроса. Таким образом, незащищённый скрипт можно использовать как прокси-сервер. Зная несколько "дырявых" сайтов, злоумышленник может выстроить из них цепочку, чтобы его было сложнее найти.

Если у провайдера, предоставляющего бесплатный демо-доступ, дырявый сайт, можно написать скрипт для домашнего сервера, который бы формировал запросы к такому прокси-серверу и экономил немного денег. Это дело, безусловно, подсудное и наказуемое, но по большому счёту баловство. Более прибыльное использование чужой машины как прокси – рассылка коммерческого спама. Например (8.2.10.3):

 

index.php?f=http%3A%2F%2Fmail.example.com%3A25%2F+HTTP/1.0%0D%0AHELO+

my.own.machine%0D%0AMAIL+FROM%3A%3Cme%40my.own.machine%3E%0D%0ARCPT+

TO%3A%3Cinfo%40site1.st%3E%0D%0ADATA%0D%0Ai+will+never+say+the+word+

PROCRASTINATE+again%0D%0A.%0D%0AQUIT%0D%0A%0D%0A

(должно быть одной строкой) модуль PHP соединится с сервером mail.example.com по 25 порту и отправит следующий запрос:

GET / HTTP/1.0\r\n

HELO my.own.machine\r\n

MAIL FROM:\r\n

RCPT TO:\r\n

DATA\r\n

i will never say the word PROCRASTINATE again\r\n

.\r\n

QUIT\r\n\r\n

 

HTTP/1.0\r\n

Host: mail.site1.st:25\r\n

User-Agent: PHP/4.1.2\r\n\r\n

 

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

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

Для начала полезно ознакомиться со списком уникальных адресов, запрашиваемых с сайта. Это поможет узнать, были ли случаи атак и использования дырки. Обычно спамеры сразу проверяют возможность соединения с нужным им почтовым релеем по 25 порту. Поэтому искать следует строки ":25" и "%3A25".

Самый простой способ отключить возможую уязвимость – запретить открывать URL через файловые функции. Если вы администратор своего сервера – запрещайте allow_url_fopen в настройках php. Если вы просто клиент – запретите у себя локально. В файле .htaccess для корня сайта напишите строку:

 

php_value allow_url_fopen 0

 

Если вы хостинг-провайдер, можете запретить URL fopen wrapper для всех клиентов при помощи директивы php_admin_value. Включение безопасного режима (safe mode) в данном случае не поможет, функция продолжает работать исправно.

Возможна такая сложная ситуация: вы клиент, а админ хостинг-провайдера вписал все установки php в php_admin_value, и поменять их нельзя. Придётся модифицировать код скриптов. Самый простой способ – искать функции fopen, file и include, открывающие файлы из имён переменных. И вырезать функцией str_replace префиксы http:// и ftp://. Впрочем, иногда скрипту, всё-таки, необходимо открывать адреса, которые приходят от пользователя. В данном случае вполне можно ограничиться вырезанием "\r\n" из полученной строки. В таком случае злоумышленник не сможет добавить свой собственный заголовок к запросу, который отправляете вы.

Клиент, сканирующий ваш сайт на предмет непроверяемых переменных, создаёт лишний трафик и загружает процессор сервера. Понятно, что ему не нужны страницы, которые генерирует ваш сайт, если они не работают как прокси. Желательно убивать такие запросы ещё до запуска php-интерпретатора. Это можно сделать при помощи модуля mod_rewrite. В файле .htaccess в корне сайта можно поставить такую строку:

 

RewriteRule ((%3A|:)25|%0D%0A) - [G]

 

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

Если вы при помощи mod_rewrite поддерживаете адресацию, удобную для чтения, то скорее всего, двоеточие и CRLF не используются. Поэтому другие строки RewriteRule не будут подходить под сканирующий запрос, и строку, прекращающую обработку запроса, лучше поместить в конце списка правил. Тогда обычные запросы будут переписываться и перенаправляться до этой строки (используйте флаг [L]), что уменьшит время их обработки. В зависимости от разных условий оно может варьироваться.

 

 

 








Не нашли, что искали? Воспользуйтесь поиском по сайту:



©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.