Сайтостроительство (8)

PHP-кодинг (25)

Веб-дизайн (9)

DHTML/JavaScript (8)

Подкастинг (1)

Безопасность в PHP (3)

Секретный раздел

Карта блога

Регистрация пользователей на PHP+MySQL

Скрипт гостевой книги с красивым дизайном

Галерея на jQuery

Простая система регистрации пользователей на сессиях

Форма обратной связи с защитой типа капча

Галерея на php+jquery

Шаблоны запросов и placeholders

Быстрое перенаправление средствами php

Flash плеер для вашего сайта

Сортировка столбцов в таблице на php+mysql

Передача переменных из JavaScript в РНР

Постраничный вывод большой статьи

Критерии качества сайта

Вертикальное меню в виде закладок

WEB 2.0 HTML-шаблоны

За весь период

За 2010-11

За 2009-06

За 2009-05

За 2009-04

За 2009-03

За 2009-02

За 2008-08

Бегун контекстная реклама

Ruseller видеоуроки

Letitbit файлообменник

Tak.Ru $$$ вебмастеру

WMmail почтовые рассылки

WMlink продажа трафика

Sape.Ru продажа ссылок

Главная » Безопасность в PHP

Шаблоны запросов и placeholders

Данная заметка является продолжением поста MySQL и проблемы безопасности.

Повторюсь, что для написания корректных запросов необходимо экранировать спецсиволы в запрашиваемых данных с помощью специальной функции mysql_escape_string(), либо использовать специальные маркеры (placeholders).

С использованием гипотетической функции mysql_qw(), код которой приведу ниже, запросы из предыдущей заметки мы могли бы переписать так:


mysql_qw('DELETE FROM table WHERE name=?', $name);

Теперь вы понимаете, почему я рекомендовал вам использовать апострофы (а не кавычки) при составлении SQL-запросов? Так вы гарантируете, что не забудите использовать mysql_escape_string() для явного экранирования переменных.

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

В листинге ниже содержится простейшая реализация функции mysql_qw().


<?
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!==null? mysql_query($query, $conn) : mysql_query($query);
}
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);
}
?>

Простейшая функция для работы с placeholder-ами result-set mysql_qw($connection_id, $query, $arg1, $arg2, ...) или result-set mysql_qw($query, $arg1, $arg2, ...) Функция выполняет запрос к MySQL через соединение, заданное как $connection_id (если не указано, то через последнее открытое).Параметр $query может содержать подстановочные знаки ?, вместо которых будут подставлены соответствующие значения аргументов $arg1, $arg2 и т.д. (по порядку), экранированные и заключенные в апострофы. А функция string mysql_make_qw($query, $arg1, $arg2, ...) формирует SQL-запрос по шаблону $query, содержащему placeholder-ы.

Примечание: Функция sprintf() воспринимает cbvdjk % как управляющий. Чтобы отменить его специальное действие, необходимо его удвоить, что и делается в функции. Затем ? заменяется на %s, для sprintf() это означает "взять очередной строковый аргумент".

Для удобства тестирования этого кода главная функция была разбита на две, тем самым выделился код замены подстановочных знаков в функцию mysql_make_qw(). В нижеприведенном листинге показан пример того, как будут выглядеть SQL-запросы после подстановки placeholders.


<?
// путь к файлу с функцией mysql_qw()
require_once "lib/mysql_qw.php";
// соединение с БД
require_once "mysql_connect.php";
$name = "' OR '1";
//допустимый
echo mysql_make_qw('DELETE FROM people WHERE name=?', $name)."<br>";
//недопустимый
echo mysql_make_qw('DELETE FROM people WHERE name=? OR ?', $name)."<br>";
//запрос
mysql_qw('DELETE FROM peple WHERE name=? OR ?', $name) or die(mysql_error());
?>

В результате работы скрипта будет сгенерирована следующая страница:


DELETE FROM people WHERE name='\' OR \'1'
DELETE FROM people WHERE name='\' OR \'1' OR UNKNOWN_PLACEHOLDER_1
Unknown column 'ONKNOWN_PLACEHOLDER_1' in 'where clause'

Как видите, перед апострофами в данных появились слэши, а placeholder, которому "не хватило" аргументов функции, оказался замененным на строчку UNKNOWN_PLACEHOLDER_1. Теперь любая попытка выполнения такого запроса заранее обречена на неудачу (о чем говорит последнее диагностическое сообщение, сгенерированное вызовом die() ), что является важным подспорьем при отладке сценариев на php.

Чтобы испробовать все примеры данной заметки, прилагаю к этому уроку архив с исходниками, в котором содержаться (помимо функции для работы с placeholders и тестового примера), также и библиотека lib/Placeholder.php, обеспечивающая значительно более мощную поддержку языка placeholders. Вы можете прочитать статью, посвященную данной библиотеке, по адресу http://dklab.ru/chicken/30.html. Впрочем, в большинстве ситуаций возможностей, предоставляемых описанной выше функцией mysql_qw(), оказывается достаточно.

В архиве, также вы найдете пример гостевой книги, реализованной с использованием этих plaseholders.

Скачать исходники этой заметки

Комментировать

Автор: admin | Добавлена: 17.05.2009 | Просмотров: 18590
Рейтинг: 14 | Голосов: 6

Оцените заметку: 1 2 3 4 5

Последние обновления в категории: Безопасность в PHP

Комментарии (0)

Комментариев пока нет!

Только авторизованные пользователи могут добавлять комментарии. Зарегистрироваться.

Логин:
Пароль:
 

Регистрация

: Тема:

Заметок в базе: 56
Комментариев: 0
Всего юзеров: 114
Сейчас онлайн: 1