Каталог статей
Поиск по базе статей  
Статья на тему Интернет » Интересное в сети » PHP: пользовательские данные

 

PHP: пользовательские данные

 

 

Каждый веб-сайт по роду своей деятельности должен принимать и обрабатывать данные от пользователей, и чем более динамическим сайт становится, тем больше «чужих» данных он использует в своей работе. Но нередко случается так, что посетители, умышленно или неумышленно, передают сайту совсем не те данные, которые он ожидает, что порой может приводить к весьма неприятным последствиям... И сегодня мы поговорим об основных приемах работы с пользовательскими данными в PHP-скриптах...

Самое главное правило заключается в том, что чужим данным нельзя доверять. Перед тем как вы будете вынуждены их использовать, обязательно проверьте соответствие переданных данных ожидаемому типу и диапазону значений.

загрузка...

 

 

Рассмотрим простой пример: пользователь запрашивает страницу сайта, передавая в качестве GET-параметра идентификатор статьи, а ваш сервер делает запрос к базе данных и «вытаскивает» эту статью. То есть адрес выглядит как:


/redir.php?url=www.mysite.ru%2Fpage.php%3Fid%3D3%26nbsp%3B%26nbsp%3B%3Cbr%3E

а запрос к базе в скрипте выполняется в виде:


$SQL = "SELECT * FROM articles WHERE id=$_GET[id]";

Такой пример будет замечательно работать, до тех пор пока кто-то не запросит страницу без параметров — в этом случае переменная $_GET[id] окажется пустой, и запрос к базе выдаст ошибку. Предположим, что вы эту ошибку решите исправить и напишете что-то вроде:


if ($_GET['id'])
$SQL = "SELECT * FROM articles WHERE id=$_GET[id]";
else
$SQL = "SELECT * FROM articles ORDER BY random() LIMIT 1";

Такой скрипт действительно корректно обработает пустой запрос — выдаст случайную статью — но что если посетитель запросит адрес:


/redir.php?url=www.mysite.ru%2Fpage.php%3Fid%3Dvasya%26nbsp%3B%26nbsp%3B%3Cbr%3E

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


$id = (isset($_GET['id'])) ? (int) $_GET['id'] : 0;
if ($id)
$SQL = "SELECT * FROM articles WHERE id=$id"
else
$SQL = "SELECT * FROM articles ORDER BY random() LIMIT 1";

Переменные надо инициализировать перед использованиемТакая конструкция гарантирует, что переменная $id у вас инициализирована и является целочисленной. Разумеется, она может выходить за пределы имеющихся статей, но тут уже после запроса к базе будет достаточно проверить количество полученных записей — это проще и менее ресурсоемко, чем при каждом вызове страницы проверять, есть ли в базе соответствующая запись.

Однако в некоторых случаях проверка разрешенного диапазона значений является необходимой. Предположим, что у вас есть скрипт, который, в зависимости от переданного пользователем параметра, читает и выдает в браузер какой-то файл:


if (file_exists($_GET['page']))
readfile($_GET['page']);
else
readfile('default.html');

PHP умеет работать с удаленными файламиКазалось бы, здесь защита предусмотрена — вы честно проверили, что запрошенный файл существует. Но на самом деле подобная конструкция является одной из наиболее типичных «уязвимостей». Дело в том, что по умолчанию PHP разрешает использовать в файловых операциях интернет-адреса, то есть пользователь может сделать запрос:


/redir.php?url=www.mysite.ru%2Fscript.php%3Fpage%3Dhttp%253A%252F%252Fdomain.ru%252Fanother_page.htm%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%3Cbr%3E

и ваш скрипт благополучно прочитает удаленную страницу. Казалось бы, в этом нет ничего особо страшного, но хитрость в том, что если эта удаленная страница содержит PHP-код, то этот чужой код будет выполнен на вашем сервере. А о том, почему это нежелательно, я думаю, рассказывать не обязательно.

Для того чтобы избежать подобной неприятности, вам надо убедиться, что запрошенная страница является корректной. Проще всего это сделать, банально перечислив разрешенные адреса (либо с помощью оператора switch, либо записав их в массив и использовав функцию in_array, либо еще как-то), а если это неприемлемо (например, таких страниц слишком много), то сделайте регекспосвскую проверку или хотя бы воспользуйтесь функцией basename(). А если вашим скриптам не требуется работать с удаленными файлами, то можно запретить PHP это делать, указав в файле php.ini allow_url_fopen = Off.

Бывают и такие ситуации, когда нет возможности проверить ни тип, ни диапазон — например, при добавлении комментариев к статьям пользователь может написать любой текст. Казалось бы, что уж здесь-то никаких опасностей быть не может — пользователь текст написал, вы его сохранили, а потом другому посетителю показали. Но именно здесь кроется еще одна распространенная уязвимость — если текст сохраняется в базе (или вообще как-то используется в SQL-запросах), то посетитель сможет выполнить свои команды! Классический пример — вы запрашиваете имя пользователя и выдаете соответствующие данные:


$SQL = "SELECT * FROM table WHERE username='$_REQUEST[user]'";

Все будет работать замечательно, до тех пор пока кто-нибудь не укажет в качестве имени пользователя что-нибудь вроде:


1'; DELETE * FROM table WHERE '1' = '1

В результате будет выполнено два запроса — первый попробует выбрать пользователя с именем 1, а второй — удалит все записи из базы...

Используйте addslashes() при работе с базой данныхАналогичная проблема может возникнуть и в том случае, если вы выполняете какие-то внешние программы, передавая пользовательские данные в качестве аргументов. Для того чтобы избежать этих неприятностей, обязательно надо использовать функцию addslashes() или ей подобную. Кроме того, для числовых значений стоит принудительно приводить их к требуемому типу c помощью, например, функции settype.

magic_quotes — это не панацеяЕсть в PHP и возможность автоматического преобразования введенных пользователем строк с помощью magiс_quotes — найдите в файле php.ini строку magic_quotes_gpc. Если значение этой переменной равно On, то во всех строках, принимаемых от пользователя, перед всеми символами апострофа, кавычек и обратного слеша (\) автоматически добавится обратный слеш, что «заэкранирует» действие этих символов. Но для полной безопасности этого недостаточно — подобное автоматическое экранирование работает только для пользовательских данных. Но если вы эти данные сохраните в базе (успешно!), а потом в другом запросе используете их, то все слеши пропадут, и вредоносный код успешно сработает! Например:


$name = $_REQUEST['name'];
$id = (int) $_REQUEST['id'];
$SQL = "INSERT INTO table (id, name) VALUES ($id, '$name');

До сих пор все работало правильно. Теперь где-то дальше вы записываете данные в лог:


$user = pg_fetch_result(pg_query($db, "SELECT name FROM table WHERE id = $id"), 0, 0);
$SQL = "INSERT INTO log_table (data, user) VALUES ('now', '$user')";

Служебные заголовки тоже могут использоваться для взлома

И вот тут-то этот вредоносный код и сработает... Поэтому стоит очень внимательно относиться ко всем данным, полученным «извне», и отслеживать их до конца. Хотя можно, разумеется, включить еще и magic_quotes_runtime (по умолчанию эта директива установлена в Off) — при этом PHP будет экранировать все данные, полученные после SQL-запросов или выполнения внешних команд. Надо только не забывать при этом использовать функцию stripslashes(), чтобы убрать лишние слеши при выводе данных.

Если ваш скрипт будет использоваться на нескольких серверах, и вы не знаете, включено ли там автоматическое экранирование, то воспользуйтесь функциями get_magic_quotes_gpc() и get_magic_quotes_runtime() соответственно — в противном случае может получиться так, что либо вы будете дважды экранировать символы, либо не будете их экранировать совсем...

При экранировании данных стоит также учесть и тот факт, что поддельными могут оказаться не только поля вашей формы, но и, скажем, referer, User-Agent и прочие «служебные» заголовки, которые вы можете захотеть сохранить в логе для последующего анализа...

Кстати, если вы показываете в браузере данные, введенные пользователем (например, все те же комментарии), то не забывайте использовать htmlspecialchars(), чтобы удалить (возможно) введенные пользователем теги HTML и JavaScript'ы...

Еще одной распространенной причиной неприятностей является использование register_globals. Эта директива указывается в php.ini и занимается тем, что регистрирует в качестве глобальных переменных данные, полученные от пользователя, с помощью методов GET, POST и COOKIE. Правда, проблемы это вызывает только в том случае, если у вас нет привычки инициализировать все переменные перед их использованием. Например, есть у вас администраторский скрипт:


if ($_REQUEST['user'] == 'admin' and $_REQUEST['password'] == 'my_very_secret_password') $admin=1;
if ($admin) {
// выполнить администраторские обязанности
} else {
// выгнать пользователя
}

Все будет работать замечательно, до тех пор пока кто-нибудь не запросит:


/redir.php?url=www.mysite.ru%2Fadmin.php%3Fadmin%3D1%26nbsp%3B%26nbsp%3B%3Cbr%3E

И еще раз: инициализируйте переменные!Как только это случится, PHP автоматически присвоит переменной $admin значение 1 (оно передано через GET), а ваш скрипт успешно обойдет первую проверку — ведь ни имя ни пароль не были переданы, и разрешит посетителю администрировать ваш сайт...

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


$var = (условие) ? значение1 : значение2;

Такая конструкция присваивает переменной $var значение1, если условие выполнено, и значение2, если нет. Например:


$page = ($_REQUEST['page']) ? (int) $_REQUEST['page'] : 1;

В этом случае вы твердо уверены, что в переменной $page хранится число, и что если страница не была указана, то переменная установлена в 1. Теперь (почти) без опаски можно использовать эту переменную в запросах к базе. А «почти» заключается в том, что не был проверен диапазон (помните, о чем писалось выше?) — наша страница вполне может оказаться отрицательной или равной нулю... Но это уже не так страшно — в худшем случае, посетитель увидит пустую страницу (так как в базе не найдется записей для отрицательной страницы), если только вы не будете что-нибудь на эту страницу делить.

В дополнение к привычке инициализировать переменные, полезно еще и отключить этот register_globals, а при отладке скриптов включать максимальный уровень предупреждений:


error_reporting(E_ALL);

Добивайтесь, чтобы исчезли не только ошибки, но и предупреждения!На этом уровне PHP будет выдавать большую кучу сообщений о неинициализированных переменных и прочих потенциально опасных вещах, что потребует от вас определенных усилий по их исправлению, зато безопасность ваших скриптов вырастет на порядок. Да и от опечаток вы будете страдать намного меньше... Надо только не забыть отключить сообщения об ошибках при загрузке скриптов на «промышленный» сервер — в противном случае, посетители смогут получить довольно много информации о внутренней структуре вашего сайта... Кстати, очень удобно бывает добавить в начало скрипта что-то вроде:


if (isset($_GET['showerrors']) && $_GET['showerrors'] == 'debug')
error_reporting(E_ALL);
else
error_reporting(0);

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



Статья получена: hostinfo.ru

 

 

Наверх


Постоянная ссылка на статью "PHP: пользовательские данные":


Рассказать другу

Оценка: 4.0 (голосов: 16)

Ваша оценка:

Ваш комментарий

Имя:
Сообщение:
Защитный код: включите графику
 
 



Поиск по базе статей:





Темы статей






Новые статьи

Противовирусные препараты: за и против Добро пожаловать в Армению. Знакомство с Арменией Крыша из сэндвич панелей для индивидуального строительства Возможно ли отменить договор купли-продажи квартиры, если он был уже подписан Как выбрать блеск для губ Чего боятся мужчины Как побороть страх перед неизвестностью Газон на участке своими руками Как правильно стирать шторы Как просто бросить курить

Вместе с этой статьей обычно читают:

Первые данные о новом Mercedes A-класса

В немецкой прессе появились первые компьютерные рисунки нового Mercedes A-класса. По сравнению с нынешним автомобилем новая «ашка» станет больше, причем намного. Если сейчас длина стандартного автомобиля составляет 3605 мм (есть еще удлиненная на 170 мм версия), то новый Mercedes A-класса будет изначально иметь длину около 3855 мм (то есть больше на 250 мм).

» Немецкие автомобили - 2217 - читать


Первые данные о новом Clio

Не дав покупателям придти в себя после премьеры Vel Satis компания Renault подготовила еще одну новинку – модель Clio, которая претерпела серьезный рейсталинг. Примечательно, что этот автомобиль по своей форме больше напоминает крохотный однообъемник, чем хэтчбек. Такая форма кузова становится все более и боле популярной, причем не только среди автомобилей среднего и малого классов.

» Французские автомобили - 1878 - читать


Инсайдерские данные о работе спутниковых систем безопасности

Не секрет, что самым эффективным средством защиты от автомобильных воров является спутниковая поисковая система. Именно с ее помощью подавляющее большинство владельцев всякого более-менее дорогого и престижного автомобиля старается защитить своего «железного коня». Однако, придя в салон, автовладелец оказывает в роли слепого, которому предлагают купить живопись.

» Разное - 2239 - читать


Таврия-2 - появились первые данные

• Новая ТаврияВ Украине идет усиленная работа по созданию новой «Таврии», которая может пойти в серию уже в 2003-2004 году. Уже даже есть первые «шпионские» фотографии этой модели, передает “Auto-Consulting”. Вообще «ЗАЗ-1102» Таврия» впервые была представлена в 1987 году в виде трехдверного хэтчбека с двигателем объемом 1,1 л.

» Разное - 2054 - читать


Секреты PHP-функций для работы с&nb p;массивами. Обработка данных и&nb p;сортировка

Итак, что же там с вашим менеджером, который был упомянут в анонсе статьи? Вы уже написали ту самую злополучную версию функции для перекодировки какого-то поля в XML-файле. Но вечером того же дня оказывается, что надо срочно поменять логику работы скрипта, который уже закачан на сервер, протестирован вашим инженерным составом и одобрен чуть ли не самим генеральным директором фирмы.

» Интересное в сети - 2176 - читать



Статья на тему Интернет » Интересное в сети » PHP: пользовательские данные

Все статьи | Разделы | Поиск | Добавить статью | Контакты

© Art.Thelib.Ru, 2006-2024, при копировании материалов, прямая индексируемая ссылка на сайт обязательна.

Энциклопедия Art.Thelib.Ru