Правильное экранирование полей и настроек запроса при использовании PDO

Возможный дубликат:
Как использовать подготовленный оператор pdo для предложений order by и limit?

Я использую PDO, поскольку он был рекомендован в качестве способа, когда дело доходит до соединений с базой данных PHP. Но в то же время я одержим защитой своих запросов, чтобы убедиться, что моя система максимально защищена от хакеров.

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

$query=$pdo->prepare('SELECT * FROM log WHERE username=?');
$result=$query->execute(array($_GET['username']));

Это работает, и все отлично — PDO заботится о том, чтобы переменная $_GET не навредила моему запросу.

Но что делать, когда мне нужно сбежать от других вещей? Например, если у меня есть такая ситуация, когда я хочу вернуть всего пять записей:

$query=$pdo->prepare('SELECT * FROM log WHERE username=? LIMIT 5');
$result=$query->execute(array($_GET['username']));

Это, опять же, работает. Но что, если предельные значения также поступают из $_GET? Как избежать этого?

Для этого я сначала понял, что мне нужно построить запрос вручную и использовать метод PDO::quote(), например:

$query='SELECT * FROM log WHERE username=? LIMIT '.$pdo->quote($_GET['limit']);

Но это не сработало, так как ограничитель заключался в кавычки, что прерывало запрос.

Есть ли правильный способ избежать PDO, как работает mysql_real_escape_string()? Поскольку последний никогда не заключает в кавычки результирующую переменную, но я не могу остановить это поведение с помощью quote().

Альтернативой было бы создание моего собственного эскейпера, но такой вид побеждает цель использования подготовленных операторов PDO для начала (сами подготовленные операторы всегда заключают значения в кавычки).

РЕДАКТИРОВАТЬ: я также попытался указать значение как целое число в кавычках, например:

$pdo->quote((int)$value,PDO::PARAM_INT);

Но он по-прежнему заключает его в кавычки. То же самое с intval().

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


person kingmaple    schedule 26.04.2012    source источник
comment
Также по теме: stackoverflow.com/questions/2683576/   -  person Brad Christie    schedule 26.04.2012


Ответы (2)


Вы обеспокоены целочисленными значениями. Поскольку $_GET всегда является строкой, вы можете преобразовать его в целое число с помощью приведения или формата %d для sprintf:

$query = $pdo->prepare(
    'SELECT * FROM log WHERE username=? LIMIT ' . (int) $_GET['page']
);

$query = $pdo->prepare(
    sprintf('SELECT * FROM log WHERE username=? LIMIT %d', $_GET['page'])
);

Если вам действительно нужна строка, подойдет функция quote(), о которой вы уже писали.

person hakre    schedule 26.04.2012
comment
Извините, но на самом деле это не решение, так как я строю запрос динамически. Это будет ужасный взлом, чтобы сделать это таким образом. На самом деле я близок к тому, чтобы сбросить PDO и вернуться к функциям mysql_*(), у которых не было этой проблемы с mysql_real_escape_string(). Мне нужно, чтобы quote() работал как с целыми, так и с нецелыми значениями, но он работает только со строками, а не с целыми числами. PDO::PARAM_INT в этом контексте бесполезен. - person kingmaple; 26.04.2012
comment
@kristovaher: В чем проблема? Вы можете сначала запустить что-то в стиле sprintf/vsprintf, чтобы создать фактический запрос, а затем использовать параметризованные запросы. Я не понимаю. - person hakre; 26.04.2012
comment
Потому что это не правильное бегство. Я хотел бы, чтобы PDO::quote() работал так же, как работает mysql_real_escape_string(), но на данный момент он заключает значение в кавычки, даже если оно является целым числом и установлено значение PDO::PARAM_INT. - person kingmaple; 26.04.2012
comment
цитата о цитировании. В случае ограничения вам нужно буквальное число. Это две вещи. - person hakre; 26.04.2012
comment
Просто приведите его к int, как в первом примере. Целые числа по своей природе безопасны и не требуют кавычек. - person Mike Caron; 26.04.2012
comment
Тогда я полагаю, что у PDO нет метода экранирования типа mysql_real_escape_string()? Хорошо, я прибегну к простому преобразованию всего в целые числа. - person kingmaple; 26.04.2012
comment
Все, что делает PDO::PARAM_INT, — это убедиться, что INT привязан к заполнителю. Существует еще абстрактный уровень процесса, когда выполняется вызов БД, который переводит запрос в выбранный драйвер БД... который, как я заметил, все еще имеет некоторые сбои. Для литеральных чисел вам необходимо создать строку запроса вручную, а затем привязать значения к заполнителям. Преимущество заключается в том, что если вы измените свой тип БД (возможно, с MySQL, учитывая), вам не нужно рефакторить все ваши вызовы БД в PHP. - person Malovich; 26.04.2012

Это отличный учебник для начинающих. Воспитывай себя.

Почему вы должны используя PHP PDO...

person Blake    schedule 26.04.2012
comment
Я развиваюсь годами. Связанная вами статья бесполезна в этом контексте и не касается вопроса, размещенного здесь. - person kingmaple; 26.04.2012
comment
Есть разница между разработкой в ​​течение многих лет и знанием всего о PDO. Наличие ресурсов ниже вашего достоинства. - person Blake; 26.04.2012
comment
stackoverflow.com/faq#etiquette - отсутствует. - person Blake; 26.04.2012