PHP-4 Эффективная работа


Уязвимые места РНР при автономной установке
Установка машины в виде модуля Apache
Безопасность файловой системы
Генерация сообщений об ошибках
Данные, вводимые пользователем
Философский взгляд на проблему
Не теряйте бдительности!

PHP представляет собой достаточно мощный язык, интерпретатор которого активизируется на стороне WWW-сервера как встроенный модуль или выполняется как отдельная CGI-программа. Для решения всех необходимых пользователю задач PHP-машина интерпретатора должна иметь возможность доступа к файлам, выполнению команд операционной системы, созданию сетевых соединений и т. д. Понятно, что эти возможности превращают РНР в потенциально опасный инструмент. И хотя РНР задумывался как более безопасное средство проектирования CGI-npограмм, чем Perl или Си, злобные личности вполне в состоянии наделать гадостей, если вы не предпримете некоторых мер безопасности. Беда грозит как со стороны пользователей вашего сервера, которым вы как администратор можете предоставить возможность размещения PHP-программ на своих страницах, так и со стороны посетителей серверов, которые могут воспользоваться другими «механизмами обмана».

Откровенно говоря, по духу РНР в чем-то напоминает Perl. В обоих языках вы всегда найдете несколько способов решить одну и ту же задачу. Но если Perl представляет собой статичную законченную и отлаженную машину, то РНР заметно гибче — в главе 1 показано, как вы можете изменять огромное число параметров конфигурации. К сожалению, у этой гибкости есть и оборотная сторона: злоумышленник также получает немало способов воздействовать на вашу систему.

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

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

20.1. Уязвимые места РНР при автономной установке

20.1.1. Уязвимые места

PHP-машина используется в качестве автономной программы CGI в тех случаях, когда вы (или администратор сервера) по каким-либо причинам не хотите включить РНР в виде модуля сервера или интегрируете РНР с другими оболочками CGI, предназначенными для создания безопасного окружения выполняемых сценариев. На практике это означает, что вы должны будете поместить интерпретатор РНР в каталог /cgi-bin/ сервера Apache. Следует отметить, что еще в 1996 году размещение интерпретаторов в этом каталоге считалось делом весьма опасным. К чему это может привести, показывают следующие два маленьких раздела.

20.1.1.1. Возможность доступа к системным файлам

Вызовы с URL формы http: //my. host/cgi -bi n/php?/etc/passwd интерпретируются следующим образом. Информация из запроса в URL после вопросительного знака передается в интерпретатор как аргумент его командной строки. Обычно интерпреаторы попросту открывают и пытаются выполнить файл, указанный в качестве первого аргумента.

внимание
       Но РНР при вызове в виде исполняемой CGI-программы отказывается интерпретировать аргументы командной строки.

20.1.1.2. Доступ к произвольным документам на сервере

При вызове вида http:// my. host/cgi-bin/php/secret/doc. html информация о пути доступа к файлу в URL после имени исполняемого файла РНР-машины обычно используется для задания имени файла, который должен быть открыт и обработан интерпретатором CGI. При этом могут использоваться отдельные директивы конфигурации сервера, которые осуществляют перенаправление документов заданного типа в PHP-машину (например, *.php). В этом случае сервер вначале проверяет права доступа к каталогу (в нашем примере — /secret), а затем генерирует новый запрос: http://my.host/cgi-bin/php/secret/script.php. К сожалению, если запрос изначально был сформулирован именно в таком виде, то сервер права доступа файла /secret/script.php не проверяет, а контролирует только права доступа файла /cgi-bin/php. Понятно, что в этом случае пользователь, имеющий право на доступ к PHP-машине /cgi-bin/php, фактически получает право доступа к произвольному документу на сервере.

внимание
       В РНР для блокирования этого вида атаки могут использоваться параметр этапа компиляции -enable-force-cgi-redirect и директивы конфигурационного файла php.ini — doc_root и user_dir.

20.1.2. Обслуживание только общедоступных файлов

Если на вашем сервере нет документов, доступ к которым ограничивается с помощью паролей или контроля IP-адресов, то использовать упомянутые выше директивы смысла нет. Если же ваш сервер не допускает перенаправления запросов, параметр --enable-force-cgi-redirect ни на что не повлияет. В любом случае вы будете уверены, что PHP-программы не будут поддаваться ни непосредственным вызовам, имеющим вид http: //my .host/cgi -bin/php/di r/script .php, ни перенаправленным, которые оформляются как http://my.host/dir/script.php.

20.1.3. Применяем --enable-force-cgi-redirect

Параметр --enable- force-cgi- redi rect, используемый при сборке РНР-машины, предотвращает попытки непосредственного использования интерпретатора РНР с помощью вызовов вида: http: //my. host/cgi -bin/php/secretdir/script. php. PHP будет анализировать такие адреса только в том случае, когда они получаются в результате перенаправления запроса сервером.

Обычно перенаправление запроса в Apache осуществляется с помощью двух директив конфигурационного файла httpd.conf.

Action php-script /cgi-bin/php
AddHandler php-script .php

20.1.4. Установка doc_root или user_dir

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

Если по каким-либо причинам вы не можете использовать метод предотвращения «самопроизвольного» перенаправления запроса, рассмотренный в предыдущем разделе, вы можете установить корень дерева PHP-программ с помощью директив doc_root конфигурационного файла или установить переменную окружения PHP_DOCUMENT_ROOT. При указании этого параметра автономный интерпретатор РНР всегда будет конструировать имя программы с префиксом, содержащимся в doc_root, что позволяет вам предотвратить выполнение программы из-за пределов указанного каталога.

Единственное исключение из этого правила определяется действием директивы user_dir. Если эта директива не используется, единственным регулятором, оказывающим влияние на имя открываемого файла, является doc_root. В этом случае выполнение запроса вида http: //my. host~/use r/doc. php не приведет к открытию файла в пользовательском домашнем каталоге, а будет предпринята попытка открыть файл с именем -user/doc.php в каталоге doc_root.

Если же параметр user_di r имеет значение, равное, например, public_php, то запрос вида http: //my. host/-use r/doc . php приведет к открытию файла с именем doc. php в каталоге public_php, расположенном в домашнем каталоге пользователя. Если, например, домашним каталогом пользователя является /home/voldemarus, то в результате всех преобразований для выполнения будет вызван файл /home/ voldemarus/public_php/doc.php.

внимание
       Расширение имени в соответствии с установками user_dir производится вне зависимости от значения doc_root, что позволяет реализовать раздельные механизмы управления деревом PHP-программ масштаба сервера и пользовательскими РНР-программами.

20.1.5. PHP-машина за пределами дерева документа

Самое надежное решение заключается в размещении исполняемого файла РНР- машины вообще за пределами дерева файлов WWW-сервера. Вы можете вынести интерпратор РНР, как и Perl, в каталог /usr/local/bin. Единственный недостаток этого решения состоит в том, что вам потребуется теперь помещать в начале каж- дого PHP-файла строку вида: #!/usr/local/bin/php

Кроме того, так же как и для Perl-программ, вам потребуется дать всем РНР-программам право на выполнение.

20.2. Установка машины в виде модуля Apache

В тех случаях, когда PHP-машина интегрирована в Apache в виде модуля, она наследует у сервера все его права на доступ к ресурсам системы, которые, как правило, ассоциируются с пользователем nobody. Этот факт оказывает на безопасность системы самое непосредственное влияние. Если вы, например, используете РНР для доступа к базе данных, то до тех пор, пока вы не примените встроенные в СУБД средства аутентификации, вы должны сделать базу данных (или отдельные таблицы/столбцы) доступной для пользователя nobody.

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

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

20.3.Безопасность файловой системы

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

Поскольку РНР ориентирован на предоставление доступа к файловой системе с правами пользователя, существует возможность создать программу РНР, которая выгружает системно значимую информацию (например, /etc/passwd), модифицирует установки интерфейсов (например, ррр0 или eth0), забивает очередь отправки электронной почты или принтера ненужными запросами и т. д., поэтому вы должны стараться максимально оградить доступ к использованию внешних ресурсов, удостоверяясь каждый раз, что задание на печать отправляет тот, кто имеет на это право.

Рассмотрим небольшой пример, в котором пользователю разрешается удалить файл из своего собственного каталога. Такая ситуация возникает, например, при организации WWW-ориентированного управления пользовательскими страничками на вашем сервере.

Вначале взгляните на то, как поступать не надо. Этот фрагмент проникнут верой в человека, в то, что он не будет (не посмеет) передавать недостоверную информацию:

     // Удаляем файл из домашнего каталога пользователя
     $username = $user_submitted_name;
     $homedir = "/home/$username";
     $file_to_delete = "$userfile";
     unlink ($homedir/$userfile);
     echo "Удален файл $file_to_delete !";
?>

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

Чтобы предотвратить подобное развитие событий, обычно предпринимаются следующие меры:

  • во-первых, пользовательским библиотекам PHP-программ предоставляются ограниченные права;
  • во-вторых, производится проверка допустимости значений всех введенных от пользователя переменных, в том числе и тех, которые поступают от автоматически сгенерированных hidden-полей.
Вот исправленная версия приведенной выше программы:
<?php
     // Удаление файлов из каталога, доступ к
     // которому разрешен пользователю

     // проверяем имя пользователя по данным сервера,
     // что предполагает использование механизма
     // аутентификации
     $username = $HTTP_REMOTE_USER;

     $homedir = "/home/$username";

     // удаляем информацию о путевых именах
     $file_to_delete = basename("$userfile");
     unlink ($homedi r/$file_to_delete);

     // фиксируем факт удаления в журнале
     // так как журнал специализированный, никаких
     // комментариев в него не пишем
     $fp = fopen("/home/logging/filedelete. log", "+a");
     $logstring = "$HTTP_REMOTE_USER $homedir $fiVe_to_delete";
     fputs ($fp, $logstring);
     fclose($fp);

     echo "Файл <t»$file_to_delete</b> удален!";
?>

Конечно, этими мерами вы можете не ограничиваться. Ничто не мешает вам вы- полнить более изощренную проверку имени введенного файла. Например, пользователь bubkin может попытаться удалить файл с именем ../. ./etc/passwd:

<?php
     $username = getenv("REMOTE_USER");
     $homedir = "/home/$username";

if (!ereg('^[^./][^/]*$', $userfile))
       die('Недопустимое имя файла $userfile');
       // не разрешаем бегать вверх-вниз по дереву каталогов
       ...
       ?>

совет
       Конечно, кроме файла паролей, над которым мы измывались на предыдущих страницах, вам необходимо подумать о защите многих других файлов. Это и другие конфиуграционные файлы в каталоге /etc, и файлы устройств в каталоге /dev/, и файлы в каталоге /home (пользователей необходимо изолировать друг от друга), и файлы баз данных, и многое, многое другое.

В общем, необходимо поступать «от обратного»: вы должны запретить все, что не разрешено явно.

назад
далее

Сайт управляется системой uCoz