Почему PDO лучше для экранирования MySQL запросов / строк запросов, чем mysql_real_escape_string? - PullRequest
48 голосов
/ 16 ноября 2009

Мне сказали, что для выхода из MySQL лучше использовать PDO, а не mysql_real_escape_string.

Может быть, у меня наступил мертвый день (или это может быть тот факт, что я нисколько не фантазирую, как естественный программист, и я все еще очень на стадии новичка, когда дело доходит до PHP) , но, проверив руководство по PHP и прочитав запись о PDO , я все еще не понимаю, что такое PDO и почему это лучше, чем использование mysql_real_escape_string. Это может быть из-за того, что я еще не справился со сложностями ООП (я предполагаю, что это как-то связано с ООП), но кроме того факта, что переменные и значения массивов, кажется, имеют перед ними двоеточие Я до сих пор не уверен, что это на самом деле и как вы используете это (и почему это лучше, чем mysql_real_escape_string. (Это также может иметь какое-то отношение к тому факту, что у меня нет четкого понимания того, что 'классы ', поэтому, когда я читаю "класс PDO", я на самом деле не мудрый).

Прочитав статью или две в разделе «Зона разработчика» на сайте MySQL, я все еще не уверен. Поскольку я даже не могу понять, что это такое в данный момент, я думаю, что, возможно, сейчас я немного его использую, но я все еще заинтересован в расширении своего образования и поиске путей улучшения.

Может ли кто-нибудь объяснить мне на «простом английском», что такое PDO (или указать мне в направлении чего-то по предмету, написанному на простом английском языке) и как вы собираетесь его использовать?

Ответы [ 6 ]

57 голосов
/ 16 ноября 2009

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

Классы PDO направлены на инкапсуляцию всей функциональности, необходимой для взаимодействия с базой данных. Они делают это путем определения «методов» (OO parlor для функций) и «properties» (OO parlor для переменных). Вы бы использовали их как полная замена для всех «стандартных» функций, которые вы используете сейчас для общения с базой данных.

Таким образом, вместо вызова ряда функций «mysql_doSomething ()» и сохранения их результатов в ваших собственных переменных, вы должны «создать экземпляр» объекта из класса PDO («класс» = абстрактное определение, «объект» = конкретный , пригодный для использования экземпляр класса) и вызов метода для этого объекта, чтобы сделать то же самое.

Например, без PDO вы бы сделали что-то вроде этого:

// Get a db connection
$connection = mysql_connect('someHost/someDB', 'userName', 'password');
// Prepare a query
$query = "SELECT * FROM someTable WHERE something = " . mysql_real_escape_string($comparison) . "'";
// Issue a query
$db_result = mysql_query($query);
// Fetch the results
$results = array();
while ($row = mysql_fetch_array($db_result)) {
  $results[] = $row;
}

в то время как это будет эквивалентно использованию PDO:

// Instantiate new PDO object (will create connection on the fly)
$db = new PDO('mysql:dbname=someDB;host=someHost');
// Prepare a query (will escape on the fly)
$statement = $db->prepare('SELECT * FROM someTable WHERE something = :comparison');
// $statement is now a PDOStatement object, with its own methods to use it, e.g.
// execute the query, passing in the parameters to replace
$statement->execute(array(':comparison' => $comparison));
// fetch results as array
$results = $statement->fetchAll();

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

Если вам нужно вместо этого обратиться к базе данных PostgreSQL, вы просто измените mysql: на pgsql: в вызывающем экземпляре new PDO(). При использовании старого метода вам придется пройти весь ваш код, заменив все функции mysql_doSomething () их аналогом pg_doSomthing () (всегда проверяя возможные различия в обработке параметров). То же самое можно сказать и о многих других поддерживаемых механизмах баз данных.

Итак, чтобы вернуться к вашему вопросу, PDO в основном просто дает вам другой способ достижения тех же самых целей, предлагая при этом некоторые ярлыки / улучшения / преимущества. Например, экранирование будет происходить автоматически надлежащим образом, необходимым для используемого вами механизма базы данных. Кроме того, подстановка параметров (предотвращение SQL-инъекций, не показанных в примере) намного проще, что делает ее менее подверженной ошибкам.

Вы должны прочитать некоторые основы ООП , чтобы получить представление о других преимуществах.

40 голосов
/ 16 ноября 2009

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

Запрос состоит из нескольких частей

Подумайте об этом так: когда вы отправляете запрос в базу данных, вы говорите ему несколько разных вещей. Например, одна вещь: «Я хочу, чтобы вы сделали выбор». Другим может быть «ограничить его строками, ГДЕ имя пользователя является следующим значением.»

Если вы создадите запрос в виде строки и передадите его в базу данных, он не узнает ни о одной из частей, пока не получит завершенную строку. Вы можете сделать это:

'SELECT * FROM transactions WHERE username=$username'

Когда он получает эту строку, он должен проанализировать ее и решить, "это SELECT с WHERE".

Смешивание деталей

Предположим, злоумышленник вводит свое имя пользователя как billysmith OR 1=1. Если вы не будете осторожны, вы можете поместить это в строку, что приведет к:

'SELECT * FROM transactions WHERE username=billysmith OR 1=1'

... что вернет всех транзакций для всех пользователей , потому что 1 всегда равно 1. Ой, вы взломаны!

Видите, что случилось? База данных не знала, какие части ожидать в вашем запросе , поэтому она просто проанализировала строку. Не было удивительно, что WHERE имел OR с двумя условиями, которые могли бы его удовлетворить.

Сохранение деталей прямыми

Если бы он только знал , что ожидать , а именно SELECT, у которого WHERE было только одно условие, злоумышленник не смог бы его обмануть.

С готовым утверждением вы можете дать ему правильное ожидание. Вы можете сказать базе данных: «Я собираюсь отправить вам SELECT, и она будет ограничена строками WHERE username = строкой, которую я собираюсь вам дать. Вот и все - других частей нет запрос. Вы готовы? Хорошо, вот строка для сравнения с именем пользователя. "

При таком ожидании база данных не будет одурачена: она будет возвращать только те строки, в которых столбец username содержит фактическую строку 'billysmith OR 1 = 1.' Если ни у кого нет этого имени пользователя, оно ничего не вернет.

Другие преимущества подготовленных заявлений

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

  • Их можно повторно использовать с различными параметрами, что должно быть быстрее, чем создание нового запроса с нуля, потому что база данных уже знает в основном то, что вы собираетесь запросить. Он уже создал свой «план запроса».
  • Некоторые базы данных (я думаю, что Postgres - одна) начнут составлять план запроса, как только они получат подготовленное утверждение - прежде чем вы фактически отправите параметры для использования с ним. Таким образом, вы можете увидеть ускорение даже при первом запросе.

Для другого объяснения см. Ответ Тео здесь .

16 голосов
/ 16 ноября 2009

В отличие от mysql_real_escape_string, PDO позволяет применять тип данных.

<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
?>

Обратите внимание, что в приведенном выше примере первый параметр, калории, должен быть целым числом (PDO :: PARAM_INT).

Во-вторых, мне кажется, что параметризованные запросы PDO легче читать. Я бы лучше прочитал:

SELECT name FROM user WHERE id = ? AND admin = ? 

чем

SELECT name FROM user WHERE id = mysql_real_escape_string($id) AND admin = mysql_real_escape_string($admin);

В-третьих, вам не нужно обязательно указывать параметры правильно. ЗОП позаботится об этом. Например, mysql_real_query_string:

SELECT * FROM user WHERE name = 'mysql_real_escape_string($name)' //note quotes around param

против

SELECT * FROM user WHERE name = ?

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

14 голосов
/ 16 ноября 2009

представьте, что вы пишете что-то вроде:

$query = 'SELECT * FROM table WHERE id = ' . mysql_real_escape_string($id);

это не спасет вас от инъекций, потому что $ id может быть 1 OR 1=1, и вы получите все записи из таблицы. вам нужно преобразовать $ id в правильный тип данных (в данном случае int)

У pdo есть еще одно преимущество - взаимозаменяемость бэкэндов базы данных.

3 голосов
/ 12 апреля 2012

Почему PDO лучше для экранирования запросов / строк запросов MySQL, чем mysql_real_escape_string?

Просто потому, что «убегать» в одиночку не имеет смысла.
Более того, это разные несравненные вопросы.

Единственная проблема с побегом состоит в том, что каждый принимает это неправильно, , считая это своего рода "защитой".
Все говорят: «Я избежал своих переменных» со значением «Я защитил свой запрос».
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * В то же время побег в одиночку не имеет никакого отношения к защите. Защита может быть примерно достигнута в случае Я сбежал и процитировал свои данные , но он не применим везде, например, для идентификаторов (как, впрочем, и для PDO).

Итак, ответ:

  • PDO при экранировании для связанных значений применяет не только экранирование, но и цитирование - поэтому лучше.
  • «побег» не является синонимом «защиты». "уклонение + цитирование" примерно равно.
  • но для некоторых частей запроса оба метода неприменимы.
3 голосов
/ 16 ноября 2009

Помимо предотвращения внедрения SQL, PDO позволяет вам подготовить запрос один раз и выполнить его несколько раз. Если ваш запрос выполняется несколько раз (например, в цикле), этот метод должен быть более эффективным (я говорю «должно быть», потому что, похоже, это не всегда так в старых версиях MySQL). Метод prepare / bind также более соответствует другим языкам, с которыми я работал.

...