Почему опасно включать параметр PHP register_globals?

« Предыдущая запись
 
  Следующая запись »
 

tf Почему опасно включать параметр PHP register globals? Не знаю почему… нет, почему нельзя включать директиву register_globals я знаю, а не знаю я почему в литературе, как правило, про это ничего не говорится.

Обычно напишут, что использовать его не рекомендуется (если вообще напишут – прим.ред.), и всё. В результате, само собой, начинающий программист просто не догадывается, к чему может привести использование register_globals.

В этой статье я постараюсь вытащить из танка всех тех, кто в нём сидит, и растолковать, что к чему (специально для тех, кто на бронепоезде – прим.ред.). Всё таки не зря некоторые хостеры отключают эту директиву. Итак…

О том, как это работает

В настройках PHP (файл php.ini) есть такая директива register_globals. Смысл её заключается в том, что если она включена (register_globals = on), то все переменные, переданные через GET и POST, будут зарегистрированы автоматически как глобальные. Что это значит?

К примеру, мы передаём сценарию index.php методом GET некоторое значение page: index.php?page=2. Переданное значение хранится в массиве GET и может быть использовано в сценарии как $_GET['page']. Однако если у нас включена register_globals, то для переданного значения будет создана переменная $page, которая доступна в любой части сценария index.php.

Небольшой итог и дополнение. При включенном register_globals создаётся три копии переменной: в массиве GET, в массиве GLOBALS и просто сама переменная ($_GET['page'], $GLOBALS['page'], $page), в то время как при выключенном register_globals переданное значение может быть доступно только через массив GET ($_GET['page']). Запомнили.

Опасность использования

Рассмотрим простой пример, чтобы понять, что нам светит (от 3 до 5 лет – прим.ред.). Чтобы было проще, скажу сразу, что $login и $password – это переменные, переданные методом GET/POST.

… $get_pass = mysql_query("SELECT 'password' FROM 'users' WHERE 'login'='".$login."' LIMIT 1");
$real_pass = mysql_fetch_array($get_pass);
if ($password==$real_pass) $check = true;
if ($check) {
echo 'Авторизация прошла успешно';

}

Кратко о том, что делает сценарий:

  • Строка 2. Делаем запрос к БД с целью вытащить настоящий пароль для введённого пользователем логина.
  • Строка 3. Получаем этот пароль и присваиваем его переменной $real_pass.
  • Строка 4. Сравниваем настоящий и введённый пароль и если они совпадут, то переменной $check будет присвоено true.
  • Строки 5-8. Если $check равен true, то пишем, что авторизация проведена успешно и т.д.

Предложенный сценарий по определению самый дырявый на свете и сейчас я покажу Вам эти дыры. Условие – register_globals включен.

Допустим, передача идёт методом GET. Тогда url будет выглядить приблизительно следующим образом:
www.site.com/index.php?login=admin&password=qwerty
Понятное дело, что сразу же создаются глобальные переменные $login и $password. А теперь посмотрите сценарий. В нём есть переменная $check. А что если её передать через урл?

www.site.com/index.php?login=admin&password=qwerty&check=1
Тогда минуется проверка соотнесения паролей и пользователь получается сразу авторизованным (ведь Вы помните, что 1 – это true, а 0 – это false?). Тот же самый результат будет, если написать www.site.com/index.php?check=1. И даже если вы используете метод POST, всё равно все подобные махинации прокатят, так как при включённом register_globals не имеет значения какой у Вас метод - GET или POST.

Думаю, у кого-то возник вопрос, а откуда крякер узнает про переменную check, что она за всё отвечает? Если Вы никому не показывали сценарий, то он врядли это узнает. Однако не все используют свои сценарии, CMS и прочее, а пользуются тем, что есть в сети. В таких случаях крякер, к примеру, может изучить код CMS и делать атаки на сайты, созданные при его помощи.

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

Возьмём наш пример. Чтобы его защитить на случай, если register_globals включен, нужно после строки if ($password==$real_pass) $check = true; дописать следующее: else $check = false;. В этом случае, даже если методом GET будет передана переменная check равная единице, то сценарий при неправильном пароле всё равно установит $check=false.

Да, ещё обращу Ваше внимание на то, что если выключить register_globals, то наш пример работать не будет. А чтобы он заработал, надо перед сценарием написать $login = $_POST['login']; $password = $_POST['password'];

 

Подведём итоги…

и сделаем два основных вывода:

1) При включённом register_globals можно передавать различные переменные, значения для которых получать через GET или POST не рассчитывалось.

2) Не столько опасен сам register_globals, сколько криво написанный сценарий.

На сегодня всё! Буду очень рад Вашим комментариям, замечаниям, предложениям и просто отзывам. Посему пишите, не стесняйтесь!

С пожеланиями удачной недели,
Александр ШУйский

,

1 звезда2 звезд3 звезд4 звезд5 звезд (голосов: 3, средний: 5.00 из 5)
Понравилась статья или журнал? Подписывайся на продолжение!
Отзывов: 14 на запись

"Почему опасно включать параметр PHP register_globals?"

  1. Почти везде по тексту идет “registry_globals” – надо бы подправить ;)

  2. ох ты, ёшкин кот, вот оно что значит писать посты на работе =)))
    спасибо за замеченные опечатки!

  3. спасибо за ценную инфу!

  4. всегда пожалуйста =)

  5. А про $_REQUEST забыл?
    “три копии переменной: в массиве GET, в массиве GLOBALS и просто сама переменная”

    не особо важно конечно, но не могу удержаться и пальцем не тыкнуть =)) Ы

  6. ЗЫ. легче не заморачиваться и всегда выключать!
    И твой код SQL инъекцией похакать можно – надо mysql_escape_string использовать.

  7. ну, я говорил о влиянии вкл/выкл register_globals, посему как-то про риквест как-то даже и не вспоминал.
    Но за комментарий и интерес отдельное спасибо =)

  8. ЗЫ: согласен, лучше вырубать.
    вообще надо обрабатыватьв се данные, передаваемые в БД. Самое безопасное strip_tags применить, а потом как раз таки заслэшить всё остальное, если таковое осталось.

  9. большое спасибо!

  10. Большое пожалуйста! =)

  11. Металлика
    04/05/2012 at 16:30 Постоянная ссылка Цитировать

    Советовали дубльстар или хуачуан, что скажете ?

  12. Александр Шуйский
    04/05/2012 at 16:51 Постоянная ссылка Цитировать

    Советую завязывать с этой шнягой 8)

  13. Виктор
    02/06/2013 at 18:21 Постоянная ссылка Цитировать

    Здравствуйте! Я воспользовался вашим сценарием. Проблема в том, что когда я передаю false (check=0), то сценарий также пишет о том, что “авторизация прошла успешно”.

  14. Александр Шуйский
    05/06/2013 at 10:55 Постоянная ссылка Цитировать

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

Добро пожаловать, коллега! Вы можете оставить свой отзыв:





Допустимые XHTML-теги:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Подписка на комментарии