Показать сообщение отдельно

  #49  
Старый 02.02.2008, 01:09
FraiDex
Участник форума
Регистрация: 16.06.2006
Сообщений: 179
С нами: 10475029

Репутация: 135
По умолчанию

intro

В этой небольшой статье я расскажу о защите о всем нам известной уязвимости SQL-injection. Данной уязвимости подвержено подавляющее большинство сайтов в сети. Суть уязвимости заключается в отсутствии фильтрации спецсимволов в параметрах, передаваемых в запросах к БД. Уязвимость позволяет злоумышленнику выполнять запросы к БД… Да лан, чё я рассказываю. В разделе статьи полно информации по SQL-injection и я изобретать велосипед не буду.  Ну что ж, перейдём к сути…

Метод №1 – Фильтрация

Этот метод заключается в фильтрации спецсимволов с помощью стандартной функции preg_match(). Данная функция будет обрабатывать параметры, передаваемые скрипту от пользователя, на соответствие параметрам, которые должны быть в запросе. Вот кусок уязвимого скрипта:
PHP код:

    
if(!empty($_GET['id']))
    {
        
        
/*Получение нужной статьи из БД*/
            
        
$query "SELECT * FROM articles WHERE id = '$_GET[id]'";
        
$result_query mysql_query($query);
        if (!
$result_query) exit("Bad parametr");
        if (
$article mysql_fetch_array($result_query))
    {
… 
А вот тот же код, только с использованием функции preg_match():

PHP код:

    
if(!empty($_GET['id']))
    {
        
        
/*Проверка переданного параметра*/
        
        
if (preg_match("|^[\d]{1,3}$|"$_GET['id']))
        {
            
            
/*Получение из БД нужной статьи*/
            
            
$query "SELECT * FROM articles WHERE id = '$_GET[id]'";
            
$result_query mysql_query($query);
            if (!
$result_query) exit("Bad parametr");
            if (
$article mysql_fetch_array($result_query))
            {

else 
    {
        
        
/*Получение из БД всех статей*/
        
        
$query "SELECT * FROM articles";
        
$result_query mysql_query($query);
        if (!
$result_query) exit("Bad parametr");
        while (
$article mysql_fetch_array($result_query))
        {
… 
Согласитесь, не сложно написать пару лишних строк в скрипт, которые смогут защитить ваш сайт от атаки.
Некоторые перци обрабатывают параметр функцией mysql_escape_ptring(), она похожа на addslashes(). Лично я такой подход не уважаю. Этот способ можно использовать лиш как способ записи корректных SQL запросов и не более того. Многие используют фцнкцию str_replace() которая вырезает все спецсимволы в параметре. Но при использование данной функции запрос всё равно будет выполнен с ложными данными, и вызовет туеву хучу ошибок.

Способ №2 – создание собственной функции обращения к БД

Согласитесь, каждый раз добавлять preg_match достаточно нудное занятие, есть способ как этого избежать. Можно написать свою функцию , которая будет отправлять запросы к БД. Вот пример от Дмитрия Котерова, библиотека содержащая в себе функцию для защиты нашего скрипта. Суть её работы в том, что она заменяет стандартную и всем нам до боли известную функцию mysql_query() своей mysql_qw(), т.е. в либе он создал функцию, заменяющую mysql_query, в которую сразу встроена проверка спецсимволов, а так же HTML-тэгов. Данный скрипт защищает как от SQL-injection, так и от XSS. Вот код библиотеки:
PHP код:
<?php ## Простейшая функция для работы с placeholder-ами.

// result-set mysql_qw($connection_id, $query, $arg1, $arg2, ...)
//  - или -
// result-set mysql_qw($query, $arg1, $arg2, ...)
// Функция выполняет запрос к MySQL через соединение, заданное как
// $connection_id (если не указано, то через последнее открытое).
// Параметр $query может содержать подстановочные знаки ?,
// вместо которых будут подставлены соответствующие значения
// аргументов $arg1, $arg2 и т.д. (по порядку), экранированные и
// заключенные в апострофы.
function mysql_qw() {
  
// Получаем все аргументы функции.
  
$args func_get_args();
  
// Если первый параметр имеет тип "ресурс", то это ID соединения.
  
$conn null;
  if (
is_resource($args[0])) $conn array_shift($args);
  
// Формируем запрос по шаблону.
  
$query call_user_func_array("mysql_make_qw"$args);
  
// Вызываем SQL-функцию.
  
return $conn!==nullmysql_query($query$conn) : mysql_query($query);
}

// string mysql_make_qw($query, $arg1, $arg2, ...)
// Данная функция формирует SQL-запрос по шаблону $query, 
// содержащему placeholder-ы.
function mysql_make_qw() {
  
$args func_get_args();
  
// Получаем в $tmpl ССЫЛКУ на шаблон запроса.
  
$tmpl =& $args[0];
  
$tmpl str_replace("%""%%"$tmpl);
  
$tmpl str_replace("?""%s"$tmpl);
  
// После этого $args[0] также окажется измененным.
  // Теперь экранируем все аргументы, кроме первого.
  
foreach ($args as $i=>$v) {
    if (!
$i) continue;        // это шаблон
    
if (is_int($v)) continue; // целые числа не нужно экранировать
    
$args[$i] = "'".mysql_escape_string($v)."'";
  }
  
// На всякий случай запорняем 20 последних аргументов недопустимыми
  // значениями, чтобы в случае, если число "?" превышает количество
  // параметров, выдавалась ошибка SQL-запроса (поможет при отладке).
  
for ($i=$c=count($args)-1$i<$c+20$i++) 
    
$args[$i+1] = "UNKNOWN_PLACEHOLDER_$i";
  
// Формируем SQL-запрос.
  
return call_user_func_array("sprintf"$args);
}
?>
Используется он так
PHP код:
include_once( "./mysq_qw.php" );

    
if(!empty($_GET['id']))
    {
        
        
/*Получение нужной статьи из БД*/
            
        
$query "SELECT * FROM articles WHERE id = '$_GET[id]'";
        
$result_query mysql_qw($query);
        if (!
$result_query) exit("Bad parametr");
        if (
$article mysql_fetch_array($result_query))
    {
… 
Конечно он староват, но работает до сих пор…

Способ №3 – Использование mod_rewrite

Этот способ заключается в использовании модуля Апача под названием mod_rewrite. И так, как же мы его будем использовать??? Все знаю как данные передаются скрипту методом GET (www.site.ru/script.php?id=1), где id содержит параметры для обращения к БД. С использование mod_rewrite можно выше приведённой ссылке придать более человеческий вид (Например: www.site.ru/script_1.html). Для этого на нужно в веб-каталоге сервера (Например: /home/site/www) создать файл .htaccess со следующим кодом:
Код:
RewriteEngine on
Options +FollowSymlinks
RewriteBase /
RewriteRule ^.htaccess$ - [F]
Таким образом мы будем запускать модуль. Теперь перейдем к замене ссылок. Добавим в конец .htaccess следующую строку:
Код:
RewriteRule http://www.site.ru/script_([0-9]*).html http://www.site.ru/script.php?id=$1
Теперь при обращении к сайту www.site.ru/script_1.html произойдёт замена на http://www.site.ru/script.php?id=1, которая в последствии будет выполнена. “А в чём же здесь защита?” спросите вы. Обратите внимание на script_([0-9]*).html, здесь у нас идёт проверка переданных скрипту параметров, т.е. как мы видим: если передаваемый параметр будет содержать кроме числовых ещё какие-нибудь символы, то запрос выполнен не будет…
Дополнительную информацию о mod_rewrite и о его использовании можно найти в документации по серверу Apache. www.apache.org

Outro
Ну вот, я кратко описал способы решения данной проблемы. Если вам есть что добавить, просьба отписать в эту тему. Всем удачи.
 
Ответить с цитированием