{% else-1 %}
(13 янв 2015, 21:38) (0/0) [0]
Ибрахим, Я * Знал, что найдется хоть один, кто процитирует мой пост и ещё такие будут. Пожалуйста.
(13 янв 2015, 14:23) (2/0) [2]
Материал предназначен в основном для начинающих веб-программистов.
Здесь я постараюсь описать как можно подробнее частые ошибки при фильтрации данных в 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 экранирует спец. символы, но она не учитывает кодировку БД и возможен обход фильтрации.
Используйте функцию 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 символам будет значительно увеличивать нагрузку на БД.

Продолжение следует. Просьба пока не писать в теме.
Добавлено 13.01.15 в 14:45:31:
Фильтрация. Ошибка №4.
Не фильтруются значения в переменной $_COOKIE.
Некоторые думаю, что раз эту переменную нельзя передать через форму, то это гарантия безопасности.
Данную переменную очень легко подделать любым
браузером, отредактировав куки сайта.
Например, в одной известной CMS была проверка, используемого шаблона сайта:
<?
if (Удалён .$_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.
Проверяйте загружаемые файлы.
Выполняйте проверку по следующим пунктам:
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 ='{$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. <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;
}
?>
В таком случаи вы предотвратите подключение файлов, которые не были вами предусмотрены.

Удалён
  • 1 из 1