Использование глобальных переменных (Register_Globals)
ВниманиеДанная возможность была
объявлена УСТАРЕВШЕЙ, начиная с PHP 5.3.0 и
была УДАЛЕНА в PHP 5.4.0.
Наверное, наиболее спорным моментом в разработке PHP
стала замена значения по умолчанию для PHP-директивы
register_globals
с ON на OFF в версии PHP
» 4.2.0.
Большинство пользователей полагались на работу этой опции, даже
не зная, что это за опция и думали, что это просто способ работы
самого PHP. Эта страница документации призвана
показать, как эта настройка сочетается с вопросами безопасности при
разработке приложений. Следует понимать, что сама по себе эта опция
никак не влияет на безопасность, угрозу представляет некорректное
использование предоставляемых ею возможностей.
В случае, если register_globals включена, то перед выполнением
вашего кода будут инициализированы различные переменные, например,
переменные, переданные при отправке HTML-формы.
Также, учитывая тот факт, что PHP не требует
инициализации переменных, написать потенциально опасный
код очень легко. Это было очень сложным решением, но сообщество
PHP решило изменить значение по умолчанию
этой директивы на OFF. Если директива включена, то при написании кода
разработчики не могли с уверенностью сказать, откуда пришла та или иная
переменная и насколько она достоверна. До такого нововведения
переменные, определяемые разработчиком внутри скрипта,
и передаваемые пользователем внешние данные могли перемешиваться.
Приведем простой пример злоупотребления конфигурационной опцией register_globals:
Пример #1 Пример опасного кода с register_globals = on
<?php
// устанавливаем переменную $authorized = true только для пользователей, прошедших авторизацию
if (authenticated_user()) {
$authorized = true;
}
// Поскольку в случае неудачи при проверке авторизации переменная $authorized
// не установлена, она может быть установлена автоматически благодаря register_globals,
// например, при 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 в приведенном ниже примере, но тогда у нас
не будет уверенности в достоверности ее значения (к примеру,
$username могла быть передана в GET-запросе
через URL).
Пример #2 Пример использования сессий со значением register_globals on или off
<?php
// Мы не знаем, откуда получена переменная $username, но точно знаем, что
// переменная $_SESSION хранит в себе данные сессии
if (isset($_SESSION['username'])) {
echo "Привет, <b>{$_SESSION['username']}</b>";
} else {
echo "Привет, <b>гость</b><br />";
echo "Вы хотите войти?";
}
?>
Также существует возможность реализации превентивных мер
в случае попытки подмены переменных. Так как во время разработки приложения
мы знаем ожидаемое значение переменной, а также знаем ее достоверное
значение, мы можем их сопоставить. Это не защитит код от подмены переменных,
но усложнит перебор возможных вариантов. Если вы не хотите знать, как именно
были получены внешние данные, используйте переменную $_REQUEST,
которая является смесью из данных GET- и POST-запросов, а также данных COOKIE.
Также, информацию об этом можно найти в разделе
внешние данные в PHP.
Пример #3 Обнаружение попытки подмены переменных
<?php
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
.
О том, как эмулировать включенное или отключенное состояние
register_globals, смотрите этот FAQ.