METANIT.COM

Фильтрация и проверка данных PHP. Частые ошибки

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

Введение.

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

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

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

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

Фильтрация. Ошибка №1
$number = $_GET['input_number']; if (intval($number))

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

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

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

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

$checkbox_arr = array_map('intval', $_POST['checkbox']);
$number = htmlspecialchars(intval($_GET['input_number']));
$number = mysql_escape_string(intval($_GET['input_number']));

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

Фильтрация. Ошибка №2.
$input_text = addslashes($_GET['input_text']);

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

$input_text = mysql_escape_string($_GET['input_text']);
$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, но достаточно подделать форму, добавив код:

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

Фильтрация. Ошибка №6.
  1. Расширение файла. Желательно запретить загрузку файлов с расширениями: php, php3, php4, php5 и т.п.
  2. Загружен ли файл на сервер move_uploaded_file
  3. Размер файла
Проверка. Ошибка №1.

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

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

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

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

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

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

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

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

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

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

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

$secret_key = md5( strtolower( "http://site.ru/" . $member['name'] . sha1($password) . date( "Ymd" ) ) ); // $secret_key - это наш хеш
if ($_POST['secret_key'] !== $secret_key)
Проверка. Ошибка №5.

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

if ($_GET['passsql'] == "password") < . вывод SQL ошибки . >else

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

Читайте также:  Как пользоваться for python
Проверка. Ошибка №5.

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

Совет.

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

UPD: Поправил пост. Перенес все советы по поводу функций и переменных, которые были в комментариях.

Источник

Php фильтрация для mysql

Подобно тому, как мы получаем все данные из таблицы, мы можем применять фильтрацию выбирать данные по определенному критерию. Для фильтрации команде SELECT передается выражение WHERE, которая принимает названия столбцов их значения в качестве критерия фильтрации. Например, получение всех данные из таблицы Users, где id = 1 :

SELECT * FROM Users WHERE >Однако если данные для фильтрации приходят извне, нам необходимо учитывать их потенциальную опасность. Рассмотрим получение данных на примере таблицы Users, созданной в прошлых, которая имеет следующее определение:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)

Объектно-ориентированный стиль

Например, мы хотим получать в GET-запросе значение для id и по нему получать из базы данных нужные данные. Определим для этого следующий скрипт user.php :

     connect_error)< die("Ошибка: " . $conn->connect_error); > $userid = $conn->real_escape_string($_GET["id"]); $sql = "SELECT * FROM Users WHERE "; if($result = $conn->query($sql))< if($result->num_rows > 0) < foreach($result as $row)< $username = $row["name"]; $userage = $row["age"]; echo "

Информация о пользователе

Имя: $username

Возраст: $userage

"; > > else< echo "
Пользователь не найден
"; > $result->free(); > else< echo "Ошибка: " . $conn->error; > $conn->close(); > ?>

Здесь через запрос GET получаем параметр id — идентификатор пользователя, который надо получить из базы данных. Однако поскольку это значение приходит извне, к нему применяется метод real_escape_string() , который экранирует спецсимволы:

$userid = $conn->real_escape_string($_GET["id"]);

Для упрощения обращения к скрипту определим скрипт index.php , который будет выводить список пользователей с ссылкой на скрипт user.php :

     

Список пользователей

connect_error)< die("Ошибка: " . $conn->connect_error); > $sql = "SELECT id, name FROM Users"; if($result = $conn->query($sql))< echo ""; foreach($result as $row)< echo ""; echo ""; echo ""; echo ""; > $result->free(); > else< echo "Ошибка: " . $conn->error; > $conn->close(); echo "
Имя
" . $row["name"] . "Подробнее
"; ?>

Таким образом, при обращении к скрипту index.php браузер отобразит список пользователей, а нажав на ссылку рядом с каждым пользователем, мы перейдем к подробному описанию:

Фильтрация данных из MySQL в PHP с помощью MySQLi

Процедурный стиль

      $userid = mysqli_real_escape_string($conn, $_GET["id"]); $sql = "SELECT * FROM Users WHERE "; if($result = mysqli_query($conn, $sql)) < if(mysqli_num_rows($result) >0) < foreach($result as $row)< $username = $row["name"]; $userage = $row["age"]; echo "

Информация о пользователе

Имя: $username

Возраст: $userage

"; > > else< echo "
Пользователь не найден
"; > mysqli_free_result($result); > else < echo "Ошибка: " . mysqli_error($conn); >mysqli_close($conn); > ?>
     

Список пользователей

$sql = "SELECT id, name FROM Users"; if($result = mysqli_query($conn, $sql))< echo ""; foreach($result as $row)< echo ""; echo ""; echo ""; echo ""; > echo "
Имя
" . $row["name"] . "Подробнее
"; mysqli_free_result($result); > else < echo "Ошибка: " . mysqli_error($conn); >mysqli_close($conn); ?>

Источник

Читайте также:  Python tuple object not callable

Php фильтрация для mysql

В прошлой статье применялся метод query() для получения всех данных из БД. Но что, если нам надо получить не все, а какие-то определенные данные, которые овечают некоторому критерию, иными словами, произвести фильтрацию данных. Например, возьмем использовавшуюся в прошлых темах таблицу Users:

CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)

Она имеет столбец id, и мы хотим получить определенный объект по id. На первый взгляд мы могли бы определить следующий код:

$sql = "SELECT * FROM Users WHERE = $conn->query($sql);

Для фильтрации команде SELECT передается выражение WHERE , которая принимает названия столбцов их значения в качестве критерия фильтрации. То есть, здесь мы получаем строке, где id = 1 .

Однако если данные для фильтрации приходят извне, например, значение для столбца id, то опять же, как и в случае с добавлением, мы сталкиваемся с потенциальной уязвимостью кода. И также, как и при добавлении, в этом случае лучше использовать параметризацию и prepared statements .

Например, мы хотим получать в GET-запросе значение для id и по нему получть из базы данных нужные данные. Определим для этого следующий скрипт user.php :

     prepare($sql); // привязываем значение параметра :userid к $_GET["id"] $stmt->bindValue(":userid", $_GET["id"]); // выполняем выражение и получаем пользователя по id $stmt->execute(); if($stmt->rowCount() > 0) < foreach ($stmt as $row) < $username = $row["name"]; $userage = $row["age"]; echo "

Информация о пользователе

Имя: $username

Возраст: $userage

"; > > else < echo "Пользователь не найден"; >> catch (PDOException $e) < echo "Database error: " . $e->getMessage(); > > ?>

Для выполнения запроса к БД вначале создаем prepared statement, которое использует параметр userid , привязанный к значению $_GET[«id»] :

$sql = "SELECT * FROM Users WHERE = $conn->prepare($sql); $stmt->bindValue(":userid", $_GET["id"]);

Далее у полученного объекта PDOStatement вызываем метод execute() , который выполняет запрос к бд:

После выполнения команды SELECT этот объект содержит полученные из БД данные, которые мы можем перебрать с помощью цикла:

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

Чтоб было проще обращаться к скрипту user.php и передавать ему id, определим скрипт index.php , который будет выводить список объектов:

     

Список пользователей

query($sql); echo ""; foreach($result as $row)< echo ""; echo ""; echo ""; echo ""; > echo "
Имя
" . $row["name"] . "Посмотреть
"; > catch (PDOException $e) < echo "Database error: " . $e->getMessage(); > ?>

Здесь все объекты из базы данных выводятся в таблицу, где второй столбец содержит ссылку на скрипт user.php , которому передается соответствующее значение id. В итоге по нажатию на эту ссылку мы перейдем к описанию объекта по id:

Источник

Оцените статью