Ключевые слова:php, security, (найти похожие документы)
From: Creator <proit@yandex.ru.>
Newsgroups: email
Date: Mon, 11 Jan 2006 14:31:37 +0000 (UTC)
Subject: Об опасности включения register_globals в PHP.
register_globals=oN? Вы в опасности!
Здравствуйте уважаемые веб-мастера, статья повествует о том, почему
опасно оставлять опцию register_globals включенной. Вы, возможно,
слышали, что использование её может привести к небезопасной работе вашей
программы (скрипта). Но давайте разберемся, как эту опцию могут
использовать в противоправных целях и как от этого защититься.
Что представляет собой register_globals?
Это опция в php.ini, которая указывает на необходимость регистрации
переменных полученные методом POST или GET в глобальный массив $GLOBALS.
Для ясности приведу пример при register_globals=on.
Есть файл "index.php" с содержимом:
<?
echo $asd.' - локальная переменная<br>';
echo $GLOBALS['asd'].' - ссылка в глобальном массиве $GLOBALS<br>';
echo $_GET['asd'].' - $_GET["asd"]';
?>
В адресной строке напишем: index.php?asd=123
Получим:
123 - локальная переменная
123 - ссылка в глобальном массиве $GLOBALS
123 - $_GET['asd']
Как мы видим, создались 2 переменные: одна локальная (+ ссылка в
$GLOBALS), другая в массиве $_GET. Многие не используют массив $_GET
вообще, они продолжают обрабатывать переменную "$asd" после получения ее
извне.
Но давайте вдумаемся, зачем нам "загрязнять" массив $GLOBALS? Для этого
у нас есть специальные массивы, хранящие данные, переданные методами GET
(массив $_GET) и POST (массив $_POST).
Тот же самый пример, но при register_globals=off :
- глобальная переменная
- ссылка в глобальном массиве $GLOBALS
123 - $_GET['asd']
Т.о. не была создана локальная переменная и для манипулирования с "$asd"
мы должны использовать массив $_GET.
Возможно, уже сейчас вы изменили свое мнение о register_globals.
Вероятно, вам придется, что-то переписать в своих программах, но оно
того стоит.
А теперь я расскажу вам, как взломщик может воспользоваться этой опцией
в своих целях, т.е. при register_globals=on
Начну от простого к сложному.
Часто мы видим предупреждения:
Notice: Undefined variable: asd(название переменной) in ****
Что это значит? Это значит, что переменная "$asd" не была определена явно.
Например, некоторые люди балуются подобным:
<?
for($i=0;$i<10;$i++)
{
@$asd.=$i;
}
echo $asd
?>
Т.е. не определив переменную, сразу начинают ее использовать.
Приведенный код по идее не страшен, но задумайтесь, а вдруг эта самая
переменная "$asd", в последствие записывается в файл? Например, напишем
следующее в строке адреса: "index.php?asd=LUSER+" и получим: "LUSER
0123456789". Ну разве приятно будет увидеть такое? Не думаю.
Предположим мы пишем систему аутентификации пользователя:
<?
if($_POST['login']=='login'&&$_POST['pass']=='pass')
{
$valid_user=TRUE; // Юзер корректный
}
if($valid_user)
{
echo 'Здравствуйте, пользователь';
}
else echo 'В доступе отказано'
?>
Привел я заведомо дырявую систему, стоит нам только написать в адресной
строке "index.php?valid_user=1" и мы получим надпись "Здравствуйте,
пользователь"
Этого бы не случилось, если бы мы написали так:
<?
if($_POST['login']=='login'&&$_POST['pass']=='pass')
{
$valid_user=TRUE; // Юзер корректный
}
else $valid_user=FALSE;
if($valid_user)
{
echo 'Здравствуйте, пользователь';
}
else echo 'В доступе отказано'
?>
Т.е. сами определили переменную $valid_user, как FALSE в случае неудачи.
Продолжим далее.
Теперь использование функции IsSet() становиться небезопасно, т.к. любой
может подменить переменную на угодную ему.
Приведу пример с sql-инъекцией:
<?
if(@$some_conditions) // некоторые условия
{
$where='id=3';
}
echo $query='SELECT id, title, description FROM table '
.'WHERE '.(IsSet($where)?$where:'id=4')
?>
В адресной строке напишем:
"index.php?where=id=0+UNION+ALL+SELECT+login,+password,+null+FROM+admin+where+login='admin'"
получим sql-инъекцию:
SELECT id, title, description FROM table WHERE id=0
UNION ALL SELECT login, password, null FROM admin where login='admin'
И взломщик получает ваши явки и пароли:(
Как вы видите все примеры, имеют дыры в защите, которые можно
эксплуатировать через включенный register_globals.
Справиться с подобным можно, если всегда определять переменную вне
зависимости от условий. Или же использовать инкапсуляцию переменных в
функциях, т.е. когда вы определяете функцию, то переменные, что внутри
нее будут закрыты извне, например:
<?
function asd()
{
// Какие то действия
if(IsSet($where))
{
echo $where;
}
else echo '$where не существует';
}
asd();
?>
Теперь, если мы напишем в адресной строке: "index.php?where=123"
Даст: "$where не существует"
Но это при условии, что вы не устанавливаете переменную $where как
глобальную, т.е. "global $where"
Я могу придумать еще очень много примеров, но думаю, что приведенных
мною вам будет достаточно для понимания.
Хочу сказать, что все эти проблемы канут в лета, когда вы установите
опцию register_globals=off и попробуете заново все приведенные выше
примеры.
Это можно сделать как в php.ini, но большинство хостинг провайдеров вам
это не позволят, потому придется воспользоваться файлом ".htaccess"
Создаем файл с названием: .htaccess
Запишем в него:
php_flag register_globals off
И все, теперь некоторые вопросы безопасности решены:)
Немного о причине написания мной этой статьи:
Лично я никогда не использовал register_globals = on, т.к. мне казалось
это нелогичным. Так же я знал, что это еще один "+" к защите. Но в
полной мере я не осознавал насколько это может быть опасно. Случилось
это когда я решил написать GSMgen - Google SiteMap generator, который
должен был работать безопасно и при включенном register_globals. Когда
же я начал его тестировать, у меня был шок.так как мне нравиться
использовать функцию IsSet() я нашел в ней непосредственную уязвимость,
и в процессе мне пришлось от этого отказаться:( Что поделаешь.
Я очень надеюсь, что эта статья изменит ваше мнение относительно
register_globals. Думаю, что со временем все хостинг провайдеры будут
ставить register_globals = off по умолчанию. Но пока этого нет, вы
знаете как с этим бороться;-)
Если у вас возникли вопросы, вы можете задать их на нашем форуме:
http://www.internet-technologies.ru/forums/ или лично мне
http://www.internet-technologies.ru/feedback.html
Удачи вам!
Источник: http://www.internet-technologies.ru (Веб-мастеру в помощь)
Статья неплохая.. Но аффтара на мыло за грамматику.
"как мне нравиться". Про проверочные слова слышал? "Что делаТЬ? нравиТЬся". А у тебя "что делаЕТ". А теперь прочитай эти слова в контексте "что делать".. сам поймешь, как нелепо это звучит.
Всегда использую ON, 9 лет опыта в php. Есть опыт написания баннерной сети, разработка CMS и скрипты специального назначения, которые должны отвечать высокой безопасности.
Главная причина использования ON - частое использование переменных из url.
По поводу примеров...
При появлении новой переменной присваиваю ей значение:
$asd может ведь вначале содержать значение "0".
Всё зависит от задачи. Лучше присвоить ей нужное значение и забыть про неё.
Далее... страшное слово "инъекции" - товарищи, это называется раздолбайством программиста!
Проверяйте каждую используемую переменную перед sql запросом и всё будет замечательно!
Элементарно:
if ($id+0 > 0 ) { ....ок..... }
if (ereg('^[a-z0-1]+$', $name)) { ....ок..... }
И ещё я обязательно "обучаю" скрипт ругаться матом, если какая-то переменная содержит левые значения.
Допускаю привычку писать так или иначе. Главное - результат и степень безопасности.
Удачи!