Reg.ru: домены и хостинг

Крупнейший регистратор и хостинг-провайдер в России.

Более 2 миллионов доменных имен на обслуживании.

Продвижение, почта для домена, решения для бизнеса.

Более 700 тыс. клиентов по всему миру уже сделали свой выбор.

Перейти на сайт->

Бесплатный Курс "Практика HTML5 и CSS3"

Освойте бесплатно пошаговый видеокурс

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

на HTML5 и CSS3 с полного нуля.

Начать->

Фреймворк Bootstrap: быстрая адаптивная вёрстка

Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.

Научитесь верстать просто, быстро и качественно, используя мощный и практичный инструмент.

Верстайте на заказ и получайте деньги.

Получить в подарок->

Бесплатный курс "Сайт на WordPress"

Хотите освоить CMS WordPress?

Получите уроки по дизайну и верстке сайта на WordPress.

Научитесь работать с темами и нарезать макет.

Бесплатный видеокурс по рисованию дизайна сайта, его верстке и установке на CMS WordPress!

Получить в подарок->

*Наведите курсор мыши для приостановки прокрутки.


Валидация и очистка данных средствами PHP

Безопасность данных является очень важным моментом, который часто недооценивается как разработчиками, так и клиентами. Начиная с PHP 5.2.0 производить очистку и валидацию данных (проверку на соответствие определенным критериям) стало проще с введением фильтрации данных. Сегодня мы рассмотрим способы фильтрации, как использовать фильтры и создадим несколько пользовательских функций.

Введение

Я всегда чувствовал, что писать код на PHP легко, а еще легче писать на PHP плохой код. Широкому распространению PHP в сфере веб-разработки способствовали многие проекты с открытым исходным кодом (open-source) вроде WordPress, Drupal, Magento. Кроме того это и веб-приложения вроде Facebook и т.д. При столь широком применении PHP (динамические веб-сайты, платформы для блоггинга, системы управления контентом, использование в приложениях для электронной коммерции и др.) вероятность столкнуться с "грязной" информацией и небезопасными системами очень велика. Данное руководство покажет некоторые методы очистки и валидации данных с помощью PHP. Мы сфокусируем внимание на нескольких типах входных данных и на том, как использовать PHP-фильтры и пользовательские функции.

Зачем очищать и проверять?

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

Хостинг

Среди основных:

- XSS (Cross-Site Scripting - Межсайтовый скриптинг)

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

- SQL-инъекция

Следующей популярной уязвимостью является другая форма инъекции кода, которая позволяет реализовывать различные виды вредоносного поведения, включая несанкционированный доступ к информации, изменение информации в базе данных либо иное нарушения нормального функционирования веб-приложения. Осуществляется данная атака путем внедрения в запрос произвольного SQL-кода, предназначенного для взаимодействия с базой данных.

- CSRF/XSRF (Cross-Site Request Forgery - Подделка межсайтовых запросов)

Данная уязвимость менее распространенная по сравнению с предыдущими. Обычно такого рода уязвимости возникают при работе с сессиями и cookies и реже - при плохо проверенных и очищенных данных. CSRF может использоваться для выполнения сайтом каких либо запросов без ведома пользователя. Один из известных способов реализации данной атаки - использование неверно сформированного атрибута src у картинки, что приводит к выполнению какого-либо скрипта, а не к отображению картинки.

- Некорректная информация

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

Перевод диалога к картинке:

- Здравствуйте, это из школы сына вас беспокоят. У нас тут неприятность с компьютерами.

- О Боже, он что, что-то сломал?

- Вашего сына действительно зовут Robert'); DROP TABLE students;?

- О, да, мы зовем его Little Bobby Tables

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

- А я надеюсь, вы научитесь проверять заносимую в базу данных информацию.

Для наших целей мы будем фокусироваться только на использовании серверных методов повышения безопасности информации, поэтому давайте посмотрим, как определяются термины "sanitization" и "validation" применительно к PHP. Обратимся к руководству по PHP:

"Валидация используется для проверки того, отвечает ли проверяемая информация определенным требованиям. Например, используя FILTER_VALIDATE_EMAIL мы определяем, является ли информация корректным (т.е. верным по структуре) e-mail-адресом, но не изменяем эти данные.

Очистка же подразумевает возможное изменение проверяемой информации, например - удаление нежелательных символов. Скажем, при использовании FILTER_SANITIZE_EMAIL будут удалены символы, которые не должны содержаться в e-mail-адресе. Т.е. в данном случае не происходит проверки корректности адреса (т.е. валидации), а удаляются заведомо неподходящие символы - не более того."

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

Какие фильтры есть у меня?

Все инсталляции PHP не могут быть идентичными. Несмотря на то, что фильтры были введены в PHP 5.2.0, не все инсталляции имеют одинаковый набор фильтров. В большинстве случаев все фильтры, о которых мы будем говорить, будут уже включены в установленный PHP на вашем сервере, но чтобы вы чуть больше знали о фильтрах, мы узнаем о том, что доступно именно на вашем сервере. В исходных кодах приложен файл getfilters.php, который, будучи однажды установленным и запущенным на сервере, отобразит список всех ваших фильтров (как фильтры информации, доступные через функцию filter_var, так и потоковые, доступные через stream_filter_append)

echo "<h1>Data Filters</h1>\n<table>\n<tr>\n";
echo "<td><strong>Filter ID</strong></td>\n";
echo "<td><strong>Filter Name</strong></td>\n</tr>";
foreach(filter_list() as $id =>$filter)
{
  echo "<tr><td>$filter</td><td>".filter_id($filter)."</td></tr>\n";
}
echo "</table>\n";

Сначала мы получаем массив, содержащий список всех доступных фильтров с помощью функции filter_list, после чего проходим циклом по массиву, выводя на экран имя фильтра и его ID.

Как мне использовать фильтр?

Фильтры PHP для валидации и очистки активируются посредством передачи функции filter_var как минимум двух параметров. В качестве примера давайте применим фильтр очистки для целого числа:

$value = '123abc456def';
echo filter_var($value, FILTER_SANITIZE_NUMBER_INT);

В этом примере у нас есть переменная value, которую мы передаем функции filter_var из расширения PHP Filters Extension, используя фильтр FILTER_SANITIZE_NUMBER_INT. В качестве результата мы получим:

123456

Фильтр очистки для целых числе удаляет все символы, не являющиеся целыми числами, выдавая нам "чистое" целое число. В исходниках вы можете попробовать различные входные данные, и к ним будет применяться ряд общих фильтров. В архив включены различные строки, которые вы можете использовать в качестве тестового материала самостоятельно.

Что делают различные фильтры?

Список ниже неполный, но он содержит большинство фильтров, которые идут в стандартной установке PHP 5.2.0+.

FILTER_VALIDATE_BOOLEAN: Проверяет, является ли переданная информация булевым значением TRUE или FALSE. Если переданное значение - значение не типа Boolean, то возвращается FALSE. Скрипт ниже выведет TRUE для примера с переменной value1 и FALSE для примера с переменной value02:

$value01 = TRUE;
if(filter_var($value01,FILTER_VALIDATE_BOOLEAN))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}
echo '<br /><br />'
$value02 = FALSE;
if(filter_var($value02,FILTER_VALIDATE_BOOLEAN))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}

FILTER_VALIDATE_EMAIL: Проверяет, является ли переданная информация корректным с точки зрения структуры e-mail адресом. Она не проверяет, существует ли этот адрес на самом деле, а только валидность адреса, т.е. правильность его структуры. Скрипт ниже выведет TRUE для примера с переменной value01 и FALSE для примера с переменной value02 (так как не хватает обязательной части со знаком @):

$value01 = 'test@example.com';
if(filter_var($value01,FILTER_VALIDATE_EMAIL))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}
echo '<br /><br />'
$value02 = 'nettuts';
if(filter_var($value02,FILTER_VALIDATE_EMAIL))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}

FILTER_VALIDATE_FLOAT: Проверяет, является ли переданное значение числом с плавающей точкой. Скрипт ниже выведет TRUE для примера с переменной value01 и FALSE для примера с переменной value02 (так как разделить "," не разрешен в числах с плавающей точкой):

Хостинг

$value01 = '1.234';
if(filter_var($value01,FILTER_VALIDATE_FLOAT))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}
echo '<br /><br />'
$value02 = '1,234';
if(filter_var($value02,FILTER_VALIDATE_FLOAT))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}

FILTER_VALIDATE_INT: Проверяет, является ли переданное значение целым числом. Скрипт ниже выведет TRUE для примера с переменной value01 и FALSE для примера с переменной value02 (десятичные числа не являются целыми):

$value01 = '123456';
if(filter_var($value01,FILTER_VALIDATE_INT))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}
echo '<br /><br />'
$value02 = '123.456';
if(filter_var($value02,FILTER_VALIDATE_INT))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}

FILTER_VALIDATE_IP: Проверяет, является ли переданное значение корректным IP-адресом. Она не проверяет, есть ли ответ от этого адреса, а лишь то, что переданное значение по своей структуре является IP-адресом. Скрипт ниже выведет TRUE для примера с переменной value01 и FALSE для примера с переменной value02:

$value01 = '192.168.0.1';
if(filter_var($value01,FILTER_VALIDATE_IP))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}
echo '<br /><br />'
$value02 = '1.2.3.4.5.6.7.8.9';
if(filter_var($value02,FILTER_VALIDATE_IP))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}

FILTER_VALIDATE_URL: Проверяет, является ли переданное значение корректным URL-адресом. Она не проверяет, она не проверяет доступность ресурса, а лишь то, что соблюдена структура URL-адреса. Скрипт ниже выведет TRUE для примера с переменной value01 и FALSE для примера с переменной value02:

$value01 = 'http://net.tutsplus.com';
if(filter_var($value01,FILTER_VALIDATE_URL))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}
echo '<br /><br />'
$value02 = 'nettuts';
if(filter_var($value02,FILTER_VALIDATE_URL))
{
  echo 'TRUE';
}
else
{
  echo 'FALSE';
}

FILTER_SANITIZE_STRING: По умолчанию данный фильтр удаляет любую некорректную или не разрешенную информацию в строке. Например, она удалит любые тэги HTML вроде <strong> или <script> из входящей строки:

$value = '<script>alert('TROUBLE HERE');</script>';
echo filter_var($value, FILTER_SANITIZE_STRING);

Данный скрипт удалит тэги и вернет следующее:

alert('TROUBLE HERE');

FILTER_SANITIZE_ENCODED: Многие программисты используют функцию urlencode(). Данный фильтр по сути выполняет те же функции. Например, следующий пример выполнит кодирование любых спецсимволов и пробелов во входящей строке:

$value = '<script>alert('TROUBLE HERE');</script>';
echo filter_var($value, FILTER_SANITIZE_ENCODED);

Скрипт закодирует пунктуацию, пробелы, скобки и вернет следующее:

%3Cscript%3Ealert%28%27TROUBLE%20HERE%27%29%3B%3C%2Fscript%3E

FILTER_SANITIZE_SPECIAL_CHARS: Данный фильтр по умолчанию производит HTML-кодирование спецсимволов вроде кавычек, амперсандов и скобок. Так как демо-страница не может явно показать это (так как HTML-кодированные спецсимволы будут проинтерпретированы браузером и отображены), вы можете увидеть это, если заглянете в исходный код:

$value = '<script>alert('TROUBLE HERE');</script>';
echo filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);

Произойдет конвертация спецсимволов в их HTML-сущности:

<script>alert('TROUBLE HERE');</script>

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

$value = 't(e)st@example.com';
echo filter_var($value, FILTER_SANITIZE_EMAIL);

Произойдет удаление скобок и вы получите на выходе свой чистый и красивый е-mail:

test@example.com

Это отличный фильтр, который можно использовать в формах для ввода e-mail, особенно в паре с FILTER_VALIDATE_EMAIL, что позволит снизить число ошибок пользователей и предотвратить атаки типа XSS.

FILTER_SANITIZE_URL: Данный фильтр похож на предыдущий. Он удаляет любые символы, недопустимые в URL. К примеру, скажем, в адресе случайно оказался знак "®". Опять же, как он туда попал - сплошная загадка.

$value = 'http://net.tuts®plus.com';
echo filter_var($value, FILTER_SANITIZE_URL);

Таким образом мы удалим ненужный знак "®" и получим нормальный адрес:

http://net.tutsplus.com

FILTER_SANITIZE_NUMBER_INT: Данный фильтр похож на FILTER_VALIDATE_INT, но вместо простой проверки на то, является ли число целым, он еще и удаляет все, что не является целым числом. Отличная вещь, особенно против надоедливых спам-ботов и обманщиков, норовящих ввести в поле какую-нибудь ерунду:

$value01 = '123abc456def';
echo filter_var($value01, FILTER_SANITIZE_NUMBER_INT);
echo '<br />';
$value02 = '1.2.3.4.5.6.7.8.9';
echo filter_var($value02, FILTER_SANITIZE_NUMBER_INT);

Оба набора символов преобразуются и на выходе получаем следующую картину:

123456
123456789

FILTER_SANITIZE_NUMBER_FLOAT: Похож на FILTER_VALIDATE_INT. Точно также позволяет добиться аналогичного эффекта:

$value01 = '123abc456def';
echo filter_var($value01, FILTER_SANITIZE_NUMBER_FLOAT);
echo '<br />';
$value02 = '1.2.3.4.5.6.7.8.9';
echo filter_var($value02, FILTER_SANITIZE_NUMBER_FLOAT);

Оба набора символов преобразуются и на выходе получаем следующую картину:

123456
123456789

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

$value = '1.23';
echo filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT);

Точка будет удалена и возвращено значение:

123

Одна из главных причин того, что фильтры FILTER_SANITIZE_NUMBER_FLOAT и FILTER_SANITIZE_INT разделены - это возможность использовать специальный флаг FILTER_FLAG_ALLOW_FRACTION, который идет как третий параметр, передаваемый функции filter_var:

$value = '1.23';
echo filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);

Так мы можем сохранить десятичную часть и получить в итоге:

1.23

Опции, флаги и контролирующие массивы - Майн Готт!

Флаг, использовавшийся в предыдущем примере - лишь один из способов получить более детальный контроль над типами данных, которые будут подвергаться очистке, определениями ограничителей, тем, как обрабатываются фильтрами массивы и др. Узнать больше про флаги и функции, используемые всвязи с применением фильтров вы можете в руководстве PHP, в части, посвященной Фильтрам - php.net/manual/en/book.filter.php.

Другие методы очистки информации средствами PHP

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

htmlspecialchars: эта функция PHP преобразует 5 специальных символов в соответствующие HTML-сущности.

Преобразованию подвергаются:

& (амперсанд)
" (двойные кавычки) когда не установлен флаг ENT_NOQUOTES
’ (одинарные кавычки) только когда установлен флаг ENT_QUOTES
< (меньше, чем)
> (больше, чем)

Используется данная функция точно так же, как и любая другая в PHP:

echo htmlspecialchars('$string');

htmlentities: Подобно функции htmlspecialchars эта функция конвертирует специальные символы в их HTML-сущности. Все отличие в том, что в данном случае конвертируются все спецсимволы, которые могут быть конвертированы. Это достаточно распространенный метод для запутывания (обфускации) e-mail-адресов от спам-ботов, так как далеко не все из них настроены на чтение html-сущностей:

echo htmlentities('$string');

mysql_real_escape_string: Это функция MySQL, помогающая защититься от атак типа SQL-инъекция. Считается хорошей практикой (а по сути необходимостью) пропускать всю информацию передаваемую SQL-запросу через эту функцию. Она экранирует все опасные спецсимволы, которые могут вызвать проблемы и стать причиной того, что little Bobby Tables уничтожит еще одну таблицу в школьной базе данных.

$query = 'SELECT * FROM table WHERE value='.mysql_real_escape_string('$string').' LIMIT 1,1';
$runQuery = mysql_query($query);

Пользовательские функции

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

function checkZipCode($value)
{
	$zipcheck = 'SELECT COUNT(*) FROM `database`.`zipcodes` WHERE                                                                                    value="'.filter_var(mysql_real_escape_string($value),FILTER_SANITIZE_NUMBER_INT).'"';
	$count = mysql_query($zipcheck);
	if($count==1)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

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

function cleanString($string)
{
	$detagged = strip_tags($string);
	if(get_magic_quotes_gpc())
	{
		$stripped = stripslashes($detagged);
		$escaped = mysql_real_escape_string($stripped);
	}
	else
	{
		$escaped = mysql_real_escape_string($detagged);
	}
	return $escaped;
}

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

Michael Owens
По материалам www.net.tutsplus.com
Перевод - Дмитрий Науменко

Исходники

P.S. Если вы хотите взять хороший старт в изучении PHP, обратите внимание на бесплатный курс по созданию своей CMS-системы на PHP с нуля. Используется объектно-ориентированный подход, поэтому вы сразу будете привыкать к хорошему:

Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!


Смотрите также:

PHP: Получение информации об объекте или классе, методах, свойствах и наследовании

PHP: Получение информации об объекте или классе, методах, свойствах и наследовании

CodeIgniter: жив или мертв?

CodeIgniter: жив или мертв?

Функции обратного вызова, анонимные функции и механизм замыканий

Функции обратного вызова, анонимные функции и механизм замыканий

Применение функции к каждому элементу массива

Применение функции к каждому элементу массива

Слияние массивов. Преобразование массива в строку

Слияние массивов. Преобразование массива в строку

Деструктор и копирование объектов с помощью метода __clone()

Деструктор и копирование объектов с помощью метода __clone()

Эволюция веб-разработчика или Почему фреймворк - это хорошо?

Эволюция веб-разработчика или Почему фреймворк - это хорошо?

Магические методы в PHP или методы-перехватчики (сеттеры, геттеры и др.)

Магические методы в PHP или методы-перехватчики (сеттеры, геттеры и др.)

PHP: Удаление элементов массива

PHP: Удаление элементов массива

Ключевое слово final (завершенные классы и методы в PHP)

Ключевое слово final (завершенные классы и методы в PHP)

50 классных сервисов, программ и сайтов для веб-разработчиков

50 классных сервисов, программ и сайтов для веб-разработчиков

Наверх