меню

Материал предназначен в основном для начинающих веб-программистов.

Введение.

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

Здесь я постараюсь описать, как можно подробнее частые ошибки при фильтрации данных в PHP скрипте и дать простые советы как правильно выполнить фильтрацию данных.

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

Разбор полетов.

 

Фильтрация в PHP. Ошибка №1

Для числовых переменных используется такая проверка:

  
$number = $_GET['input_number'];
if (intval($number))
{
... выполняем SQL запрос ...
}
  

Почему она приведет к SQL инъекции? Дело в том, что пользователь может указать в переменной input_number значение:

 
1'+UNION+SELECT    
  

В таком случаи проверка будет успешно пройдена, т.к. функция intval получает целочисленное значение переменной, т.е. 1, но в самой переменной $number ничего не изменилось, поэтому весь вредоносный код будет передан в SQL запрос. Правильная фильтрация:


$number = intval($_GET['input_number']);
if ($number)
{
... выполняем SQL запрос ...
}

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


if ($number >= 32 AND $number <= 65)

Если вы используете чекбоксы или мультиселекты с числовыми значениями, выполните такую проверку:


$checkbox_arr = array_map('intval', $_POST['checkbox']);

array_map

Так же встречаю фильтрацию в виде:


$number = htmlspecialchars(intval($_GET['input_number']));

htmlspecialchars

Или:


$number = mysql_escape_string(intval($_GET['input_number']));

mysql_escape_string

Ничего кроме улыбки это не может вызвать :)

Фильтрация. Ошибка №2.

Для стринг-переменных используется такая фильтрация:

  
$input_text = addslashes($_GET['input_text']);    
  

Функция addslashes экранирует спец. символы, но она не учитывает кодировку БД и возможен обход фильтрации. Не стану копировать текст автора, который описал данную уязвимость и дам просто ссылку Chris Shiflett (перевод можно поискать в рунете).

Используйте функцию mysql_escape_string или mysql_real_escape_string, пример:

 

  
$input_text = mysql_escape_string($_GET['input_text']);   
  

Если вы не предполагаете вхождение html тегов, то лучше всего сделать такую фильтрацию:

  
$input_text = strip_tags($_GET['input_text']);
$input_text = htmlspecialchars($input_text);
$input_text = mysql_escape_string($input_text);

strip_tags — убирает html теги.
htmlspecialchars — преобразует спец. символы в html сущности.
Так вы защитите себя от XSS атаки, помимо SQL инъекции.
Если же вам нужны html теги, но только как для вывода исходного кода, то достаточно использовать:
$input_text = htmlspecialchars($_GET['input_text']);
$input_text = mysql_escape_string($input_text);

Если вам важно, чтобы значение переменной не было пустой, то используйте функцию trim, пример:
$input_text = trim($_GET['input_text']);
$input_text = htmlspecialchars($input_text);
$input_text = mysql_escape_string($input_text); 
  

Фильтрация. Ошибка №3.

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

 
$input_text = htmlspecialchars($_GET['input_text']); // Поиск: "%"
$input_text = mysql_escape_string($input_text);   
  

На выходе у нас получится запрос вида:

 
... WHERE text_row LIKE '%".$input_text."%' ... // WHERE text_row LIKE '%%%'    
  

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

 
function strip_data($text)
{
    $quotes = array ("\x27", "\x22", "\x60", "\t", "\n", "\r", "*", "%", "<", ">", "?", "!" );
    $goodquotes = array ("-", "+", "#" );
    $repquotes = array ("\-", "\+", "\#" );
    $text = trim( strip_tags( $text ) );
    $text = str_replace( $quotes, '', $text );
    $text = str_replace( $goodquotes, $repquotes, $text );
    $text = ereg_replace(" +", " ", $text);
            
    return $text;
}
 

Конечно, не все из выше перечисленных символов представляют опасность, но в моём случаи они не нужны, поэтому выполняю поиск и замену. Пример использования фильтрации:

  
$input_text = strip_data($_GET['input_text']);
$input_text = htmlspecialchars($input_text);
$input_text = mysql_escape_string($input_text);
 

Также советую сделать ограничение по количеству символов в поиске, хотя бы не меньше 3-х, т.к. если у вас будет большое количество записей в базе, то поиск по 1-2 символам будет значительно увеличивать нагрузку на БД.

Фильтрация. Ошибка №4.

Не фильтруются значения в переменной $_COOKIE. Некоторые думаю, что раз эту переменную нельзя передать через форму, то это гарантия безопасности.

Данную переменную очень легко подделать любым браузером, отредактировав куки сайта. Например, в одной известной CMS была проверка, используемого шаблона сайта:

  
if (@is_dir ( MAIN_DIR . '/template/' . $_COOKIE['skin'] )){
  $config['skin'] = $_COOKIE['skin'];
}
$tpl->dir = MAIN_DIR . '/template/' . $config['skin'];   
  

В данном случаи можно подменить значение переменной $_COOKIE['skin'] и вызвать ошибку, в результате которой вы увидите абсолютный путь до папки сайта.

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

Фильтрация. Ошибка №5.

Включена директива register_globals. Обязательно выключите её, если она включена. В некоторых ситуациях можно передать значение переменной, которая не должна была передаваться, например, если на сайте есть группы, то группе 2 переменная $group должна быть пустой или равняться 0, но достаточно подделать форму, добавив код:

 
<input type="text" name="group" value="5" />    
  

В PHP скрипте переменная $group будет равна 5, если в скрипте она не была объявлена со значением по умолчанию.

Фильтрация. Ошибка №6.

Проверяйте загружаемые файлы. Расширение файла. Желательно запретить загрузку файлов с расширениями: php, php3, php4, php5 и т.п. Загружен ли файл на сервер move_uploaded_file. Размер файла.

Проверка. Ошибка №1.

Сталкивался со случаями, когда для AJAX запроса (например: повышение репутации) передавалось имя пользователя или его ID (кому повышается репутация), но в самом PHP не было проверки на существование такого пользователя. Например:

 
$user_id = intval($_REQUEST['user_id']);
... INSERT INTO REPLOG SET uid = '{$user_id}', plus = '1' ...
... UPDATE Users SET reputation = reputation+1 WHERE user_id = '{$user_id}' ...    
  

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

Проверка. Ошибка №2.

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

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

Проверка. Ошибка №3.

При использовании нескольких php файлов сделайте простую проверку. В файле index.php (или в любом другом главном файле) напишите такую строчку перед подключением других php файлов:

  
  define ( 'READFILE', true );
  

В начале других php файлов напишите:

 
if (! defined ( 'READFILE' ))
{
  exit ( "Error, wrong way to file.<br><a href=\"/\">Go to main</a>." );
}   
  

Так вы ограничите доступ к файлам.

Проверка. Ошибка №4.

Используйте хеши для пользователей. Это поможет предотвратить вызов той или иной функции путём XSS. Пример составления хеша для пользователей:

 
$secret_key = md5( strtolower( "http://site.ru/" . $member['name'] . sha1($password) . date( "Ymd" ) ) ); // $secret_key - это наш хеш    
  

Далее во все важные формы подставляйте инпут со значением текущего хеша пользователя:

  
<input type="hidden" name="secret_key" value="$secret_key" />   
  

Во время выполнения скрипта осуществляйте проверку:

  
if ($_POST['secret_key'] !== $secret_key)
{
exit ('Error: secret_key!');
}   
  

Проверка. Ошибка №5.

При выводе SQL ошибок сделайте простое ограничение к доступу информации. Например задайте пароль для GET переменной:

  
if ($_GET['passsql'] == "password")
{
... вывод SQL ошибки ...
}
else
{
... Просто информация об ошибке, без подробностей ...
}  
  

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

Проверка. Ошибка №5.

Старайтесь не подключать файлы, получая имена файлов извне. Например:

 
if (isset($_GET['file_name']))
{
include $_GET['file_name'] .'.php';
}   
  

Используйте переключатель switch:

  
switch($_GET['file_name'])
{         
         case 'file_1':
         include 'file_1.php';    
         break;     
         
         default:
         include 'file_0.php';    
         break;
}   
  

В таком случаи вы предотвратите подключение файлов, которые не были вами предусмотрены.

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

Возможно, вам будет интересно

Простая гостевая книга на PHP

Результат, который мы получим, можно использовать на своей страничке, в качестве скрипта отзывов или еще чего-то подобного. Статья ориентирована на то, что вы уже знакомы с PHP и MySQL, т.е. знаете азы.

Создание веб сервиса на PHP

Веб-служба, веб-сервис (англ. web service) — идентифицируемая уникальным веб-адресом (URL-адресом) программная система со стандартизированными интерфейсами, а также HTML-документ сайта, отображаемый браузером пользователя. (Материал из Википедии)

Подходящий поиск на php

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

Как получить HTTP заголовки сервера?

Привычная схема клиент-серверного взаимодействия, это когда клиент – отправляет запрос, сервер возвращает ответ. Давайте рассмотрим пример, как можно просмотреть возвращаемые HTTP заголовки сервера, при запросе.

Оформление заявки

Документы на создание сайта

Изучите наше коммерческое предложение, заполните БРИФ и отправьте его на почту maxidebox@list.ru. Изучив все пожелания из БРИФ-а, обратным ответом оповестим Вас по стоимости разработке, ответим на вопросы.

КП на создание сайта Коммерческое предложение на созданеи сайта

Мы берем на себя ответственность за все стадии работы и полностью избавляем клиентов от забот и необходимости вникать в тонкости.

Скачать БРИФ (акета) на создание сайта Скачать БРИФ (акета) на создание сайта

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